Compare commits
	
		
			452 Commits
		
	
	
		
			pull-input
			...
			pull-gtk-2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | fa7a1e5219 | ||
|  | f50def915e | ||
|  | 0a337ed067 | ||
|  | 932f2d7e0f | ||
|  | b780bf8eff | ||
|  | 1a2858995d | ||
|  | e2bb4ae746 | ||
|  | 4380be0e99 | ||
|  | fec0da9cbf | ||
|  | ec15993d9d | ||
|  | 6b1dd54b6a | ||
|  | a10678b08e | ||
|  | 6998b6c11b | ||
|  | d1180c1e57 | ||
|  | 89218c218f | ||
|  | fc4bde9025 | ||
|  | 029ad4bcf3 | ||
|  | e3a17ef6cc | ||
|  | f46b9cc71c | ||
|  | c1d7572793 | ||
|  | a1fa7992a9 | ||
|  | f9b5426fd5 | ||
|  | 7179585688 | ||
|  | 831f4d27b6 | ||
|  | 49bba868df | ||
|  | 2a802aaf63 | ||
|  | ef18c2f54e | ||
|  | 3048ed6aac | ||
|  | fa15286a75 | ||
|  | 6ab57a6b80 | ||
|  | 3334e929ae | ||
|  | 333cb18ff4 | ||
|  | a1d2db08d8 | ||
|  | 7b0140e49b | ||
|  | bbd8bb8e32 | ||
|  | de13d21614 | ||
|  | 66ad0893f0 | ||
|  | 79afc36d91 | ||
|  | bcb2b582f3 | ||
|  | 6449a41a4d | ||
|  | a2689242b1 | ||
|  | 4cb88c3c37 | ||
|  | 08da527fd0 | ||
|  | f068d320de | ||
|  | 7721a30442 | ||
|  | 14ac573392 | ||
|  | 3b1a413812 | ||
|  | d3afacc726 | ||
|  | f6fe04d566 | ||
|  | be56f04eea | ||
|  | 5acc765c04 | ||
|  | aa633469ed | ||
|  | 130f2e7dcb | ||
|  | da5141fc45 | ||
|  | 25f748e37a | ||
|  | fb8ad9f2c1 | ||
|  | 46d9dfdad6 | ||
|  | 411bdc7837 | ||
|  | 4e624edaeb | ||
|  | 526d0096e5 | ||
|  | f1ecb913d8 | ||
|  | d615efac7c | ||
|  | 8d5c773e32 | ||
|  | bf01601764 | ||
|  | 61e9924149 | ||
|  | 4a331bb33b | ||
|  | a35d9be622 | ||
|  | 5b808275f3 | ||
|  | 82432638eb | ||
|  | 80ff35cd3f | ||
|  | 26896cbf35 | ||
|  | 7efea76377 | ||
|  | b167383ffb | ||
|  | 8597f2e19e | ||
|  | b44672849a | ||
|  | 40e76f736d | ||
|  | 5dfc05cb1d | ||
|  | 959e41473f | ||
|  | 37654d9e6a | ||
|  | 08397c4b29 | ||
|  | a373cdb5ce | ||
|  | aa0f607f61 | ||
|  | 95faaa73df | ||
|  | e8198f6ea0 | ||
|  | 8c6d96728d | ||
|  | 04bb4d86f1 | ||
|  | 2e95fa1719 | ||
|  | 1ad166b612 | ||
|  | 5db15096d0 | ||
|  | d34bda716a | ||
|  | 5d039baba4 | ||
|  | b544c1aba8 | ||
|  | 405a27640b | ||
|  | 50809c8b92 | ||
|  | 4e627aeef8 | ||
|  | 26edf8cc08 | ||
|  | 31e25e3e57 | ||
|  | ae74bbe7c5 | ||
|  | f38b161203 | ||
|  | fd7fbc8ff7 | ||
|  | ea9a6606b1 | ||
|  | 01b91ac2be | ||
|  | d4ad9dec14 | ||
|  | 366d4f7e00 | ||
|  | e09c49f40d | ||
|  | 9d48d3f01c | ||
|  | 9f0355b590 | ||
|  | d4f005db9b | ||
|  | 711e2f1e9e | ||
|  | 9f9260a3be | ||
|  | 16b96f82cd | ||
|  | b09481de91 | ||
|  | de431a655a | ||
|  | eaad03e472 | ||
|  | e2a32ebbfe | ||
|  | e7e898a76a | ||
|  | e8f6d00c30 | ||
|  | b728464ae8 | ||
|  | c1eb2fa3fd | ||
|  | 77549a7809 | ||
|  | b052e4509b | ||
|  | 870a706735 | ||
|  | 7c82256006 | ||
|  | 487cad8853 | ||
|  | 00cc3e1d70 | ||
|  | 843408b3cf | ||
|  | f57584dc87 | ||
|  | 8a201bd47e | ||
|  | 81cf8d8adc | ||
|  | 43773ed369 | ||
|  | c773828aa9 | ||
|  | f08b617018 | ||
|  | 1d854765df | ||
|  | 58ed270df9 | ||
|  | 0f590e749f | ||
|  | d94f0a8ecb | ||
|  | 93e22326d6 | ||
|  | ca0aa40816 | ||
|  | a6c9eac0d5 | ||
|  | 859d76120b | ||
|  | 0983979b3a | ||
|  | fddbd80cc9 | ||
|  | 7e4e88656c | ||
|  | e3eb9806c7 | ||
|  | 3d1b2ff62c | ||
|  | 76782fab1c | ||
|  | 0b91966730 | ||
|  | d6635c4dbb | ||
|  | 1ac362cdbd | ||
|  | b15446fdbf | ||
|  | 22524f7262 | ||
|  | 13af91ebf0 | ||
|  | c9f87b20b9 | ||
|  | 5a05cbeeaa | ||
|  | 6d7e73d62f | ||
|  | db519cba87 | ||
|  | 76ef2cf549 | ||
|  | 8d242f0ed5 | ||
|  | 0d6ecec252 | ||
|  | 580b6b2aa2 | ||
|  | c75f3bdf46 | ||
|  | 2af0b20056 | ||
|  | 84390bed59 | ||
|  | ea80019149 | ||
|  | 85ebd381fd | ||
|  | 99cc598924 | ||
|  | abd269b7cf | ||
|  | c2f3426c9b | ||
|  | e3625d3d6a | ||
|  | a8c868c386 | ||
|  | 471799d135 | ||
|  | 69447cd8f3 | ||
|  | 80cf625766 | ||
|  | 6ee50af24b | ||
|  | 63f0f45f2e | ||
|  | 9d94020bc6 | ||
|  | 7e1efdf0a3 | ||
|  | dcd042282d | ||
|  | 9b536adcbe | ||
|  | ed78cda3de | ||
|  | 2572b37a47 | ||
|  | 924fe1293c | ||
|  | 79b6f2f651 | ||
|  | 2082bac151 | ||
|  | 90525fe279 | ||
|  | 3503206a90 | ||
|  | 2deb4acc7c | ||
|  | 5a165668e7 | ||
|  | 2e377f1730 | ||
|  | be1a717624 | ||
|  | 374044f08f | ||
|  | 9b1786829a | ||
|  | f522d2acc5 | ||
|  | e00fcfeab3 | ||
|  | 278073ba29 | ||
|  | 82ea61c6da | ||
|  | 1673e89e93 | ||
|  | 3257fc8383 | ||
|  | 36f5db59cf | ||
|  | 7bafd8889e | ||
|  | b52991537c | ||
|  | 4006617552 | ||
|  | cf864569cd | ||
|  | 7bd3055ffd | ||
|  | b791c3b38c | ||
|  | 322fd1f4f7 | ||
|  | b88a3e01f5 | ||
|  | d81d410635 | ||
|  | 381626a969 | ||
|  | 95dd1c4d7a | ||
|  | 9a1d111e70 | ||
|  | ad489e9346 | ||
|  | f2335791fd | ||
|  | 363f59d9e4 | ||
|  | bdef972474 | ||
|  | 50ef467923 | ||
|  | f72b49398f | ||
|  | 9bb931802e | ||
|  | 55d492d760 | ||
|  | 0e1dac6c41 | ||
|  | 5e70018b00 | ||
|  | 0688448b71 | ||
|  | 3df3e0a587 | ||
|  | 279a35ab4a | ||
|  | 7532d3cbf1 | ||
|  | 12e1129b80 | ||
|  | 078c44f48e | ||
|  | 4cb47d281a | ||
|  | c13959c745 | ||
|  | 675036e4da | ||
|  | bb9cd2ee99 | ||
|  | 2df5fee2db | ||
|  | b122c3b6d0 | ||
|  | 6262bbd363 | ||
|  | f25391c2a6 | ||
|  | 3cb0e25c4b | ||
|  | 6376f95223 | ||
|  | 543f7bef13 | ||
|  | 29f2601aa6 | ||
|  | 443422fde7 | ||
|  | b20e61e0d5 | ||
|  | a1904e48c4 | ||
|  | 75e347d66a | ||
|  | ebee92b4fe | ||
|  | d7d3d6092c | ||
|  | 66226ffd05 | ||
|  | 24666baf1f | ||
|  | a62f6f5600 | ||
|  | ae18b28dd1 | ||
|  | d2e16f2ce1 | ||
|  | 1695974187 | ||
|  | 3d9bddb30b | ||
|  | e9a9a5b605 | ||
|  | 2c90784abf | ||
|  | 011209e19f | ||
|  | bbb8a1b455 | ||
|  | afb49896fa | ||
|  | 72866e823e | ||
|  | a5ed2de10a | ||
|  | 836d6ed96e | ||
|  | c017230d9b | ||
|  | 944eea962b | ||
|  | 2ef6175aa7 | ||
|  | a763551ad5 | ||
|  | de77914e50 | ||
|  | a5f54290ce | ||
|  | 6b1b144019 | ||
|  | a199b2b6a5 | ||
|  | 1d10b44546 | ||
|  | 13d7adf92a | ||
|  | 3ef9622182 | ||
|  | 0380aef323 | ||
|  | 3ee933c9d4 | ||
|  | 052367ba85 | ||
|  | adbfc34103 | ||
|  | 972b09c219 | ||
|  | fbab9ccbdb | ||
|  | efde4b6252 | ||
|  | e67c399363 | ||
|  | dc83cd427b | ||
|  | 7d2d3e74e5 | ||
|  | 318df29e10 | ||
|  | 356b4ca2bb | ||
|  | dfb12bf86e | ||
|  | d11c8917b2 | ||
|  | 68c70af16d | ||
|  | 5496fb1aeb | ||
|  | 5f0c39e598 | ||
|  | 4618e658e6 | ||
|  | 01c2b265fc | ||
|  | 04bc7c0e38 | ||
|  | d61563b235 | ||
|  | 3775ec6f5a | ||
|  | b1422f2040 | ||
|  | e8817e7b0e | ||
|  | 6815bce542 | ||
|  | ce782938b8 | ||
|  | 826b6ca0b0 | ||
|  | 920beae103 | ||
|  | 8d24cce1e3 | ||
|  | 628ff68303 | ||
|  | 3718d8ab65 | ||
|  | fbe40ff780 | ||
|  | 8574575f90 | ||
|  | 0bf7488afb | ||
|  | 271c0f68b4 | ||
|  | bd60436936 | ||
|  | 4ba6fabfb4 | ||
|  | 7cf6376ae8 | ||
|  | 53651ec26b | ||
|  | 109519fd32 | ||
|  | 4aa23452e3 | ||
|  | 9474ab1487 | ||
|  | 2f21ff25c0 | ||
|  | eb386aaccc | ||
|  | 501f28ca9d | ||
|  | 27aa948502 | ||
|  | a1ba125c0c | ||
|  | d42e3c26cd | ||
|  | 855ea66dd5 | ||
|  | 61d4b215d1 | ||
|  | db6c3cd0e7 | ||
|  | 14c521d45e | ||
|  | 7ab6c10d00 | ||
|  | 81547d6630 | ||
|  | 3b685ba7bf | ||
|  | 1fe8141ed4 | ||
|  | cca7c2f523 | ||
|  | 2a923c4dde | ||
|  | 28c9457df0 | ||
|  | 1b1742386c | ||
|  | 73fb3b764b | ||
|  | 68fdb6c5b0 | ||
|  | d81c519c40 | ||
|  | 6947f05978 | ||
|  | f79fbf39e2 | ||
|  | 6ce2faf43c | ||
|  | c119779543 | ||
|  | a99caa48d8 | ||
|  | 9d4c4e872e | ||
|  | f0aff25570 | ||
|  | fc37b7a0b0 | ||
|  | 9ef137cad6 | ||
|  | 93f94f9018 | ||
|  | 00d0f7cb66 | ||
|  | 57a740514d | ||
|  | ca3164df4d | ||
|  | 433d33c555 | ||
|  | 1687a089f1 | ||
|  | 116d554601 | ||
|  | 1fba509527 | ||
|  | 69e995040c | ||
|  | 8d1bd3c901 | ||
|  | 56a9f18051 | ||
|  | b664b80f19 | ||
|  | 19e8393170 | ||
|  | 22513a9b44 | ||
|  | 68206d7342 | ||
|  | 36084d7e31 | ||
|  | f995523582 | ||
|  | 058fdcf52c | ||
|  | 463c534db5 | ||
|  | 6fa2769751 | ||
|  | 82fc18099a | ||
|  | 0f61a61df3 | ||
|  | 3158a3482b | ||
|  | aa0a55d42d | ||
|  | 0c77a37f11 | ||
|  | 99623c90d1 | ||
|  | 2884cf5b93 | ||
|  | 4eeaa3a885 | ||
|  | 746b867030 | ||
|  | 4c638e2e4b | ||
|  | 1c856da57b | ||
|  | 74444bc198 | ||
|  | cdeb7090ee | ||
|  | d3ef575080 | ||
|  | 6a24ced5ca | ||
|  | ed1132e41a | ||
|  | e3500d1f5f | ||
|  | 271a25c0b6 | ||
|  | 832189c9b1 | ||
|  | 0fb20d1c39 | ||
|  | ee5f31e48b | ||
|  | 6fe83074d7 | ||
|  | 3f9a6e852e | ||
|  | fd07d07ba9 | ||
|  | aea7947c74 | ||
|  | b35e3ba01a | ||
|  | 521a580d23 | ||
|  | afff2b15e8 | ||
|  | d09b8fa161 | ||
|  | 38dbd48b24 | ||
|  | 25156d1061 | ||
|  | 4e7d30a22a | ||
|  | f7bbcfb5c3 | ||
|  | a946ce8020 | ||
|  | b6bfeea92a | ||
|  | 33fac20bb2 | ||
|  | 3401fd259e | ||
|  | 1db1c4d7d9 | ||
|  | 9a2f0bfe32 | ||
|  | c068896f7f | ||
|  | fd1cf66630 | ||
|  | 4f048535cd | ||
|  | 741f117d9a | ||
|  | 22ee3a987d | ||
|  | 070603f62b | ||
|  | ac0f3b1263 | ||
|  | 1c4182687e | ||
|  | f216a35f36 | ||
|  | 6c530e32f4 | ||
|  | 418839044e | ||
|  | fbef2cc80f | ||
|  | ce0236cfbd | ||
|  | 9d8bf2d125 | ||
|  | f9a716325f | ||
|  | 7dae901d2d | ||
|  | f8c9eddb2b | ||
|  | 483c76e140 | ||
|  | 479eb12108 | ||
|  | 42119fa356 | ||
|  | 26b78f4d3c | ||
|  | f33a984d51 | ||
|  | fa5912a17b | ||
|  | 124fe7fb1b | ||
|  | d357e3d9d2 | ||
|  | 5b9d313e3f | ||
|  | 8cd05ab65a | ||
|  | 9c132c7f64 | ||
|  | 0971f1bed2 | ||
|  | b645000e1a | ||
|  | e35f29ded3 | ||
|  | 1a3de8dbec | ||
|  | 9e04c683fc | ||
|  | 5672ee54d5 | ||
|  | 36af599417 | ||
|  | aef553fdca | ||
|  | 78a4b8d205 | ||
|  | a3abb29292 | ||
|  | 28fb26f19f | ||
|  | 7125c937c9 | ||
|  | d3b5491897 | ||
|  | b98dbc9095 | ||
|  | 87446327cc | ||
|  | b763adf1a6 | ||
|  | 7c8b724826 | ||
|  | 0d73394ad9 | ||
|  | 84351843eb | ||
|  | fb5be2e833 | ||
|  | 13cc2c3e86 | ||
|  | a096b3a673 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ | ||||
| /config-host.* | ||||
| /config-target.* | ||||
| /config.status | ||||
| /config-temp | ||||
| /trace/generated-tracers.h | ||||
| /trace/generated-tracers.c | ||||
| /trace/generated-tracers-dtrace.h | ||||
|   | ||||
| @@ -66,16 +66,16 @@ matrix: | ||||
|       compiler: gcc | ||||
|     # All the trace backends (apart from dtrace) | ||||
|     - env: TARGETS=i386-softmmu,x86_64-softmmu | ||||
|            EXTRA_CONFIG="--enable-trace-backend=stderr" | ||||
|            EXTRA_CONFIG="--enable-trace-backends=stderr" | ||||
|       compiler: gcc | ||||
|     - env: TARGETS=i386-softmmu,x86_64-softmmu | ||||
|            EXTRA_CONFIG="--enable-trace-backend=simple" | ||||
|            EXTRA_CONFIG="--enable-trace-backends=simple" | ||||
|       compiler: gcc | ||||
|     - env: TARGETS=i386-softmmu,x86_64-softmmu | ||||
|            EXTRA_CONFIG="--enable-trace-backend=ftrace" | ||||
|            EXTRA_CONFIG="--enable-trace-backends=ftrace" | ||||
|            TEST_CMD="" | ||||
|       compiler: gcc | ||||
|     - env: TARGETS=i386-softmmu,x86_64-softmmu | ||||
|           EXTRA_PKGS="liblttng-ust-dev liburcu-dev" | ||||
|           EXTRA_CONFIG="--enable-trace-backend=ust" | ||||
|           EXTRA_CONFIG="--enable-trace-backends=ust" | ||||
|       compiler: gcc | ||||
|   | ||||
| @@ -243,8 +243,8 @@ S: Maintained | ||||
| F: hw/*/exynos* | ||||
|  | ||||
| Calxeda Highbank | ||||
| M: Mark Langsdorf <mark.langsdorf@calxeda.com> | ||||
| S: Supported | ||||
| M: Rob Herring <robh@kernel.org> | ||||
| S: Maintained | ||||
| F: hw/arm/highbank.c | ||||
| F: hw/net/xgmac.c | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @@ -52,12 +52,12 @@ GENERATED_HEADERS += trace/generated-events.h | ||||
| GENERATED_SOURCES += trace/generated-events.c | ||||
|  | ||||
| GENERATED_HEADERS += trace/generated-tracers.h | ||||
| ifeq ($(TRACE_BACKEND),dtrace) | ||||
| ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) | ||||
| GENERATED_HEADERS += trace/generated-tracers-dtrace.h | ||||
| endif | ||||
| GENERATED_SOURCES += trace/generated-tracers.c | ||||
|  | ||||
| ifeq ($(TRACE_BACKEND),ust) | ||||
| ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) | ||||
| GENERATED_HEADERS += trace/generated-ust-provider.h | ||||
| GENERATED_SOURCES += trace/generated-ust.c | ||||
| endif | ||||
|   | ||||
| @@ -49,7 +49,7 @@ endif | ||||
| $(QEMU_PROG).stp-installed: $(SRC_PATH)/trace-events | ||||
| 	$(call quiet-command,$(TRACETOOL) \ | ||||
| 		--format=stap \ | ||||
| 		--backend=$(TRACE_BACKEND) \ | ||||
| 		--backends=$(TRACE_BACKENDS) \ | ||||
| 		--binary=$(bindir)/$(QEMU_PROG) \ | ||||
| 		--target-name=$(TARGET_NAME) \ | ||||
| 		--target-type=$(TARGET_TYPE) \ | ||||
| @@ -58,7 +58,7 @@ $(QEMU_PROG).stp-installed: $(SRC_PATH)/trace-events | ||||
| $(QEMU_PROG).stp: $(SRC_PATH)/trace-events | ||||
| 	$(call quiet-command,$(TRACETOOL) \ | ||||
| 		--format=stap \ | ||||
| 		--backend=$(TRACE_BACKEND) \ | ||||
| 		--backends=$(TRACE_BACKENDS) \ | ||||
| 		--binary=$(realpath .)/$(QEMU_PROG) \ | ||||
| 		--target-name=$(TARGET_NAME) \ | ||||
| 		--target-type=$(TARGET_TYPE) \ | ||||
|   | ||||
							
								
								
									
										33
									
								
								arch_init.c
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								arch_init.c
									
									
									
									
									
								
							| @@ -739,7 +739,6 @@ static void migration_end(void) | ||||
|     XBZRLE_cache_lock(); | ||||
|     if (XBZRLE.cache) { | ||||
|         cache_fini(XBZRLE.cache); | ||||
|         g_free(XBZRLE.cache); | ||||
|         g_free(XBZRLE.encoded_buf); | ||||
|         g_free(XBZRLE.current_buf); | ||||
|         XBZRLE.cache = NULL; | ||||
| @@ -975,12 +974,12 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host) | ||||
|     xh_len = qemu_get_be16(f); | ||||
|  | ||||
|     if (xh_flags != ENCODING_FLAG_XBZRLE) { | ||||
|         fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n"); | ||||
|         error_report("Failed to load XBZRLE page - wrong compression!"); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     if (xh_len > TARGET_PAGE_SIZE) { | ||||
|         fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n"); | ||||
|         error_report("Failed to load XBZRLE page - len overflow!"); | ||||
|         return -1; | ||||
|     } | ||||
|     /* load data and decode */ | ||||
| @@ -989,7 +988,7 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host) | ||||
|     /* decode RLE */ | ||||
|     if (xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host, | ||||
|                              TARGET_PAGE_SIZE) == -1) { | ||||
|         fprintf(stderr, "Failed to load XBZRLE page - decode error!\n"); | ||||
|         error_report("Failed to load XBZRLE page - decode error!"); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
| @@ -1006,7 +1005,7 @@ static inline void *host_from_stream_offset(QEMUFile *f, | ||||
|  | ||||
|     if (flags & RAM_SAVE_FLAG_CONTINUE) { | ||||
|         if (!block) { | ||||
|             fprintf(stderr, "Ack, bad migration stream!\n"); | ||||
|             error_report("Ack, bad migration stream!"); | ||||
|             return NULL; | ||||
|         } | ||||
|  | ||||
| @@ -1022,7 +1021,7 @@ static inline void *host_from_stream_offset(QEMUFile *f, | ||||
|             return memory_region_get_ram_ptr(block->mr) + offset; | ||||
|     } | ||||
|  | ||||
|     fprintf(stderr, "Can't find block %s!\n", id); | ||||
|     error_report("Can't find block %s!", id); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| @@ -1075,10 +1074,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) | ||||
|                 QTAILQ_FOREACH(block, &ram_list.blocks, next) { | ||||
|                     if (!strncmp(id, block->idstr, sizeof(id))) { | ||||
|                         if (block->length != length) { | ||||
|                             fprintf(stderr, | ||||
|                                     "Length mismatch: %s: " RAM_ADDR_FMT | ||||
|                                     " in != " RAM_ADDR_FMT "\n", id, length, | ||||
|                                     block->length); | ||||
|                             error_report("Length mismatch: %s: " RAM_ADDR_FMT | ||||
|                                          " in != " RAM_ADDR_FMT, id, length, | ||||
|                                          block->length); | ||||
|                             ret =  -EINVAL; | ||||
|                             goto done; | ||||
|                         } | ||||
| @@ -1087,8 +1085,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) | ||||
|                 } | ||||
|  | ||||
|                 if (!block) { | ||||
|                     fprintf(stderr, "Unknown ramblock \"%s\", cannot " | ||||
|                             "accept migration\n", id); | ||||
|                     error_report("Unknown ramblock \"%s\", cannot " | ||||
|                                  "accept migration", id); | ||||
|                     ret = -EINVAL; | ||||
|                     goto done; | ||||
|                 } | ||||
| @@ -1243,12 +1241,11 @@ void select_soundhw(const char *optarg) | ||||
|  | ||||
|             if (!c->name) { | ||||
|                 if (l > 80) { | ||||
|                     fprintf(stderr, | ||||
|                             "Unknown sound card name (too big to show)\n"); | ||||
|                     error_report("Unknown sound card name (too big to show)"); | ||||
|                 } | ||||
|                 else { | ||||
|                     fprintf(stderr, "Unknown sound card name `%.*s'\n", | ||||
|                             (int) l, p); | ||||
|                     error_report("Unknown sound card name `%.*s'", | ||||
|                                  (int) l, p); | ||||
|                 } | ||||
|                 bad_card = 1; | ||||
|             } | ||||
| @@ -1271,13 +1268,13 @@ void audio_init(void) | ||||
|         if (c->enabled) { | ||||
|             if (c->isa) { | ||||
|                 if (!isa_bus) { | ||||
|                     fprintf(stderr, "ISA bus not available for %s\n", c->name); | ||||
|                     error_report("ISA bus not available for %s", c->name); | ||||
|                     exit(1); | ||||
|                 } | ||||
|                 c->init.init_isa(isa_bus); | ||||
|             } else { | ||||
|                 if (!pci_bus) { | ||||
|                     fprintf(stderr, "PCI bus not available for %s\n", c->name); | ||||
|                     error_report("PCI bus not available for %s", c->name); | ||||
|                     exit(1); | ||||
|                 } | ||||
|                 c->init.init_pci(pci_bus); | ||||
|   | ||||
							
								
								
									
										14
									
								
								async.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								async.c
									
									
									
									
									
								
							| @@ -117,15 +117,21 @@ void qemu_bh_schedule_idle(QEMUBH *bh) | ||||
|  | ||||
| void qemu_bh_schedule(QEMUBH *bh) | ||||
| { | ||||
|     AioContext *ctx; | ||||
|  | ||||
|     if (bh->scheduled) | ||||
|         return; | ||||
|     ctx = bh->ctx; | ||||
|     bh->idle = 0; | ||||
|     /* Make sure that idle & any writes needed by the callback are done | ||||
|      * before the locations are read in the aio_bh_poll. | ||||
|     /* Make sure that: | ||||
|      * 1. idle & any writes needed by the callback are done before the | ||||
|      *    locations are read in the aio_bh_poll. | ||||
|      * 2. ctx is loaded before scheduled is set and the callback has a chance | ||||
|      *    to execute. | ||||
|      */ | ||||
|     smp_wmb(); | ||||
|     smp_mb(); | ||||
|     bh->scheduled = 1; | ||||
|     aio_notify(bh->ctx); | ||||
|     aio_notify(ctx); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -105,7 +105,7 @@ static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate) | ||||
|     bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ()); | ||||
|     samples = (bytes - rate->bytes_sent) >> info->shift; | ||||
|     if (samples < 0 || samples > 65536) { | ||||
|         fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples); | ||||
|         error_report("Resetting rate control (%" PRId64 " samples)", samples); | ||||
|         rate_start (rate); | ||||
|         samples = 0; | ||||
|     } | ||||
|   | ||||
| @@ -63,8 +63,7 @@ static void wav_destroy (void *opaque) | ||||
|         } | ||||
|     doclose: | ||||
|         if (fclose (wav->f)) { | ||||
|             fprintf (stderr, "wav_destroy: fclose failed: %s", | ||||
|                      strerror (errno)); | ||||
|             error_report("wav_destroy: fclose failed: %s", strerror(errno)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -59,6 +59,7 @@ typedef struct BlkMigDevState { | ||||
|     unsigned long *aio_bitmap; | ||||
|     int64_t completed_sectors; | ||||
|     BdrvDirtyBitmap *dirty_bitmap; | ||||
|     Error *blocker; | ||||
| } BlkMigDevState; | ||||
|  | ||||
| typedef struct BlkMigBlock { | ||||
| @@ -361,7 +362,8 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs) | ||||
|         bmds->completed_sectors = 0; | ||||
|         bmds->shared_base = block_mig_state.shared_base; | ||||
|         alloc_aio_bitmap(bmds); | ||||
|         bdrv_set_in_use(bs, 1); | ||||
|         error_setg(&bmds->blocker, "block device is in use by migration"); | ||||
|         bdrv_op_block_all(bs, bmds->blocker); | ||||
|         bdrv_ref(bs); | ||||
|  | ||||
|         block_mig_state.total_sector_sum += sectors; | ||||
| @@ -599,7 +601,8 @@ static void blk_mig_cleanup(void) | ||||
|     blk_mig_lock(); | ||||
|     while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { | ||||
|         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry); | ||||
|         bdrv_set_in_use(bmds->bs, 0); | ||||
|         bdrv_op_unblock_all(bmds->bs, bmds->blocker); | ||||
|         error_free(bmds->blocker); | ||||
|         bdrv_unref(bmds->bs); | ||||
|         g_free(bmds->aio_bitmap); | ||||
|         g_free(bmds); | ||||
| @@ -626,6 +629,7 @@ static int block_save_setup(QEMUFile *f, void *opaque) | ||||
|             block_mig_state.submitted, block_mig_state.transferred); | ||||
|  | ||||
|     qemu_mutex_lock_iothread(); | ||||
|     init_blk_migration(f); | ||||
|  | ||||
|     /* start track dirty blocks */ | ||||
|     ret = set_dirty_tracking(); | ||||
| @@ -635,8 +639,6 @@ static int block_save_setup(QEMUFile *f, void *opaque) | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     init_blk_migration(f); | ||||
|  | ||||
|     qemu_mutex_unlock_iothread(); | ||||
|  | ||||
|     ret = flush_blks(f); | ||||
|   | ||||
							
								
								
									
										297
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										297
									
								
								block.c
									
									
									
									
									
								
							| @@ -179,6 +179,7 @@ void bdrv_io_limits_enable(BlockDriverState *bs) | ||||
| { | ||||
|     assert(!bs->io_limits_enabled); | ||||
|     throttle_init(&bs->throttle_state, | ||||
|                   bdrv_get_aio_context(bs), | ||||
|                   QEMU_CLOCK_VIRTUAL, | ||||
|                   bdrv_throttle_read_timer_cb, | ||||
|                   bdrv_throttle_write_timer_cb, | ||||
| @@ -335,6 +336,7 @@ void bdrv_register(BlockDriver *bdrv) | ||||
| BlockDriverState *bdrv_new(const char *device_name, Error **errp) | ||||
| { | ||||
|     BlockDriverState *bs; | ||||
|     int i; | ||||
|  | ||||
|     if (bdrv_find(device_name)) { | ||||
|         error_setg(errp, "Device with id '%s' already exists", | ||||
| @@ -353,12 +355,16 @@ BlockDriverState *bdrv_new(const char *device_name, Error **errp) | ||||
|     if (device_name[0] != '\0') { | ||||
|         QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list); | ||||
|     } | ||||
|     for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { | ||||
|         QLIST_INIT(&bs->op_blockers[i]); | ||||
|     } | ||||
|     bdrv_iostatus_disable(bs); | ||||
|     notifier_list_init(&bs->close_notifiers); | ||||
|     notifier_with_return_list_init(&bs->before_write_notifiers); | ||||
|     qemu_co_queue_init(&bs->throttled_reqs[0]); | ||||
|     qemu_co_queue_init(&bs->throttled_reqs[1]); | ||||
|     bs->refcnt = 1; | ||||
|     bs->aio_context = qemu_get_aio_context(); | ||||
|  | ||||
|     return bs; | ||||
| } | ||||
| @@ -1090,6 +1096,37 @@ fail: | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd) | ||||
| { | ||||
|  | ||||
|     if (bs->backing_hd) { | ||||
|         assert(bs->backing_blocker); | ||||
|         bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker); | ||||
|     } else if (backing_hd) { | ||||
|         error_setg(&bs->backing_blocker, | ||||
|                    "device is used as backing hd of '%s'", | ||||
|                    bs->device_name); | ||||
|     } | ||||
|  | ||||
|     bs->backing_hd = backing_hd; | ||||
|     if (!backing_hd) { | ||||
|         error_free(bs->backing_blocker); | ||||
|         bs->backing_blocker = NULL; | ||||
|         goto out; | ||||
|     } | ||||
|     bs->open_flags &= ~BDRV_O_NO_BACKING; | ||||
|     pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename); | ||||
|     pstrcpy(bs->backing_format, sizeof(bs->backing_format), | ||||
|             backing_hd->drv ? backing_hd->drv->format_name : ""); | ||||
|  | ||||
|     bdrv_op_block_all(bs->backing_hd, bs->backing_blocker); | ||||
|     /* Otherwise we won't be able to commit due to check in bdrv_commit */ | ||||
|     bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, | ||||
|                     bs->backing_blocker); | ||||
| out: | ||||
|     bdrv_refresh_limits(bs); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Opens the backing file for a BlockDriverState if not yet open | ||||
|  * | ||||
| @@ -1103,6 +1140,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) | ||||
|     char *backing_filename = g_malloc0(PATH_MAX); | ||||
|     int ret = 0; | ||||
|     BlockDriver *back_drv = NULL; | ||||
|     BlockDriverState *backing_hd; | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     if (bs->backing_hd != NULL) { | ||||
| @@ -1125,30 +1163,26 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) | ||||
|         bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX); | ||||
|     } | ||||
|  | ||||
|     backing_hd = bdrv_new("", errp); | ||||
|  | ||||
|     if (bs->backing_format[0] != '\0') { | ||||
|         back_drv = bdrv_find_format(bs->backing_format); | ||||
|     } | ||||
|  | ||||
|     assert(bs->backing_hd == NULL); | ||||
|     ret = bdrv_open(&bs->backing_hd, | ||||
|     ret = bdrv_open(&backing_hd, | ||||
|                     *backing_filename ? backing_filename : NULL, NULL, options, | ||||
|                     bdrv_backing_flags(bs->open_flags), back_drv, &local_err); | ||||
|     if (ret < 0) { | ||||
|         bs->backing_hd = NULL; | ||||
|         bdrv_unref(backing_hd); | ||||
|         backing_hd = NULL; | ||||
|         bs->open_flags |= BDRV_O_NO_BACKING; | ||||
|         error_setg(errp, "Could not open backing file: %s", | ||||
|                    error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         goto free_exit; | ||||
|     } | ||||
|  | ||||
|     if (bs->backing_hd->file) { | ||||
|         pstrcpy(bs->backing_file, sizeof(bs->backing_file), | ||||
|                 bs->backing_hd->file->filename); | ||||
|     } | ||||
|  | ||||
|     /* Recalculate the BlockLimits with the backing file */ | ||||
|     bdrv_refresh_limits(bs); | ||||
|     bdrv_set_backing_hd(bs, backing_hd); | ||||
|  | ||||
| free_exit: | ||||
|     g_free(backing_filename); | ||||
| @@ -1196,6 +1230,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, | ||||
|                        bdref_key); | ||||
|             ret = -EINVAL; | ||||
|         } | ||||
|         QDECREF(image_options); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
| @@ -1784,8 +1819,9 @@ void bdrv_close(BlockDriverState *bs) | ||||
|  | ||||
|     if (bs->drv) { | ||||
|         if (bs->backing_hd) { | ||||
|             bdrv_unref(bs->backing_hd); | ||||
|             bs->backing_hd = NULL; | ||||
|             BlockDriverState *backing_hd = bs->backing_hd; | ||||
|             bdrv_set_backing_hd(bs, NULL); | ||||
|             bdrv_unref(backing_hd); | ||||
|         } | ||||
|         bs->drv->bdrv_close(bs); | ||||
|         g_free(bs->opaque); | ||||
| @@ -1822,7 +1858,11 @@ void bdrv_close_all(void) | ||||
|     BlockDriverState *bs; | ||||
|  | ||||
|     QTAILQ_FOREACH(bs, &bdrv_states, device_list) { | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|         aio_context_acquire(aio_context); | ||||
|         bdrv_close(bs); | ||||
|         aio_context_release(aio_context); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1847,17 +1887,6 @@ static bool bdrv_requests_pending(BlockDriverState *bs) | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| static bool bdrv_requests_pending_all(void) | ||||
| { | ||||
|     BlockDriverState *bs; | ||||
|     QTAILQ_FOREACH(bs, &bdrv_states, device_list) { | ||||
|         if (bdrv_requests_pending(bs)) { | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Wait for pending requests to complete across all BlockDriverStates | ||||
|  * | ||||
| @@ -1877,12 +1906,20 @@ void bdrv_drain_all(void) | ||||
|     BlockDriverState *bs; | ||||
|  | ||||
|     while (busy) { | ||||
|         QTAILQ_FOREACH(bs, &bdrv_states, device_list) { | ||||
|             bdrv_start_throttled_reqs(bs); | ||||
|         } | ||||
|         busy = false; | ||||
|  | ||||
|         busy = bdrv_requests_pending_all(); | ||||
|         busy |= aio_poll(qemu_get_aio_context(), busy); | ||||
|         QTAILQ_FOREACH(bs, &bdrv_states, device_list) { | ||||
|             AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|             bool bs_busy; | ||||
|  | ||||
|             aio_context_acquire(aio_context); | ||||
|             bdrv_start_throttled_reqs(bs); | ||||
|             bs_busy = bdrv_requests_pending(bs); | ||||
|             bs_busy |= aio_poll(aio_context, bs_busy); | ||||
|             aio_context_release(aio_context); | ||||
|  | ||||
|             busy |= bs_busy; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1945,13 +1982,14 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, | ||||
|     bs_dest->refcnt             = bs_src->refcnt; | ||||
|  | ||||
|     /* job */ | ||||
|     bs_dest->in_use             = bs_src->in_use; | ||||
|     bs_dest->job                = bs_src->job; | ||||
|  | ||||
|     /* keep the same entry in bdrv_states */ | ||||
|     pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name), | ||||
|             bs_src->device_name); | ||||
|     bs_dest->device_list = bs_src->device_list; | ||||
|     memcpy(bs_dest->op_blockers, bs_src->op_blockers, | ||||
|            sizeof(bs_dest->op_blockers)); | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -1986,7 +2024,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) | ||||
|     assert(QLIST_EMPTY(&bs_new->dirty_bitmaps)); | ||||
|     assert(bs_new->job == NULL); | ||||
|     assert(bs_new->dev == NULL); | ||||
|     assert(bs_new->in_use == 0); | ||||
|     assert(bs_new->io_limits_enabled == false); | ||||
|     assert(!throttle_have_timer(&bs_new->throttle_state)); | ||||
|  | ||||
| @@ -2005,7 +2042,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old) | ||||
|     /* Check a few fields that should remain attached to the device */ | ||||
|     assert(bs_new->dev == NULL); | ||||
|     assert(bs_new->job == NULL); | ||||
|     assert(bs_new->in_use == 0); | ||||
|     assert(bs_new->io_limits_enabled == false); | ||||
|     assert(!throttle_have_timer(&bs_new->throttle_state)); | ||||
|  | ||||
| @@ -2038,19 +2074,14 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top) | ||||
|  | ||||
|     /* The contents of 'tmp' will become bs_top, as we are | ||||
|      * swapping bs_new and bs_top contents. */ | ||||
|     bs_top->backing_hd = bs_new; | ||||
|     bs_top->open_flags &= ~BDRV_O_NO_BACKING; | ||||
|     pstrcpy(bs_top->backing_file, sizeof(bs_top->backing_file), | ||||
|             bs_new->filename); | ||||
|     pstrcpy(bs_top->backing_format, sizeof(bs_top->backing_format), | ||||
|             bs_new->drv ? bs_new->drv->format_name : ""); | ||||
|     bdrv_set_backing_hd(bs_top, bs_new); | ||||
| } | ||||
|  | ||||
| static void bdrv_delete(BlockDriverState *bs) | ||||
| { | ||||
|     assert(!bs->dev); | ||||
|     assert(!bs->job); | ||||
|     assert(!bs->in_use); | ||||
|     assert(bdrv_op_blocker_is_empty(bs)); | ||||
|     assert(!bs->refcnt); | ||||
|     assert(QLIST_EMPTY(&bs->dirty_bitmaps)); | ||||
|  | ||||
| @@ -2232,7 +2263,8 @@ int bdrv_commit(BlockDriverState *bs) | ||||
|         return -ENOTSUP; | ||||
|     } | ||||
|  | ||||
|     if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) { | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, NULL) || | ||||
|         bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, NULL)) { | ||||
|         return -EBUSY; | ||||
|     } | ||||
|  | ||||
| @@ -2323,12 +2355,17 @@ int bdrv_commit_all(void) | ||||
|     BlockDriverState *bs; | ||||
|  | ||||
|     QTAILQ_FOREACH(bs, &bdrv_states, device_list) { | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|         aio_context_acquire(aio_context); | ||||
|         if (bs->drv && bs->backing_hd) { | ||||
|             int ret = bdrv_commit(bs); | ||||
|             if (ret < 0) { | ||||
|                 aio_context_release(aio_context); | ||||
|                 return ret; | ||||
|             } | ||||
|         } | ||||
|         aio_context_release(aio_context); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| @@ -2636,13 +2673,11 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top, | ||||
|     if (ret) { | ||||
|         goto exit; | ||||
|     } | ||||
|     new_top_bs->backing_hd = base_bs; | ||||
|  | ||||
|     bdrv_refresh_limits(new_top_bs); | ||||
|     bdrv_set_backing_hd(new_top_bs, base_bs); | ||||
|  | ||||
|     QSIMPLEQ_FOREACH_SAFE(intermediate_state, &states_to_delete, entry, next) { | ||||
|         /* so that bdrv_close() does not recursively close the chain */ | ||||
|         intermediate_state->bs->backing_hd = NULL; | ||||
|         bdrv_set_backing_hd(intermediate_state->bs, NULL); | ||||
|         bdrv_unref(intermediate_state->bs); | ||||
|     } | ||||
|     ret = 0; | ||||
| @@ -2748,10 +2783,12 @@ static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset, | ||||
|         /* Fast-path if already in coroutine context */ | ||||
|         bdrv_rw_co_entry(&rwco); | ||||
|     } else { | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|         co = qemu_coroutine_create(bdrv_rw_co_entry); | ||||
|         qemu_coroutine_enter(co, &rwco); | ||||
|         while (rwco.ret == NOT_DONE) { | ||||
|             qemu_aio_wait(); | ||||
|             aio_poll(aio_context, true); | ||||
|         } | ||||
|     } | ||||
|     return rwco.ret; | ||||
| @@ -3494,8 +3531,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) | ||||
|         return -ENOTSUP; | ||||
|     if (bs->read_only) | ||||
|         return -EACCES; | ||||
|     if (bdrv_in_use(bs)) | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) { | ||||
|         return -EBUSY; | ||||
|     } | ||||
|     ret = drv->bdrv_truncate(bs, offset); | ||||
|     if (ret == 0) { | ||||
|         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); | ||||
| @@ -3803,10 +3841,15 @@ int bdrv_flush_all(void) | ||||
|     int result = 0; | ||||
|  | ||||
|     QTAILQ_FOREACH(bs, &bdrv_states, device_list) { | ||||
|         int ret = bdrv_flush(bs); | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|         int ret; | ||||
|  | ||||
|         aio_context_acquire(aio_context); | ||||
|         ret = bdrv_flush(bs); | ||||
|         if (ret < 0 && !result) { | ||||
|             result = ret; | ||||
|         } | ||||
|         aio_context_release(aio_context); | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| @@ -3997,10 +4040,12 @@ int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num, | ||||
|         /* Fast-path if already in coroutine context */ | ||||
|         bdrv_get_block_status_co_entry(&data); | ||||
|     } else { | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|         co = qemu_coroutine_create(bdrv_get_block_status_co_entry); | ||||
|         qemu_coroutine_enter(co, &data); | ||||
|         while (!data.done) { | ||||
|             qemu_aio_wait(); | ||||
|             aio_poll(aio_context, true); | ||||
|         } | ||||
|     } | ||||
|     return data.ret; | ||||
| @@ -4593,7 +4638,7 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, | ||||
|     acb->is_write = is_write; | ||||
|     acb->qiov = qiov; | ||||
|     acb->bounce = qemu_blockalign(bs, qiov->size); | ||||
|     acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); | ||||
|     acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_aio_bh_cb, acb); | ||||
|  | ||||
|     if (is_write) { | ||||
|         qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size); | ||||
| @@ -4632,13 +4677,14 @@ typedef struct BlockDriverAIOCBCoroutine { | ||||
|  | ||||
| static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb) | ||||
| { | ||||
|     AioContext *aio_context = bdrv_get_aio_context(blockacb->bs); | ||||
|     BlockDriverAIOCBCoroutine *acb = | ||||
|         container_of(blockacb, BlockDriverAIOCBCoroutine, common); | ||||
|     bool done = false; | ||||
|  | ||||
|     acb->done = &done; | ||||
|     while (!done) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(aio_context, true); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -4675,7 +4721,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque) | ||||
|             acb->req.nb_sectors, acb->req.qiov, acb->req.flags); | ||||
|     } | ||||
|  | ||||
|     acb->bh = qemu_bh_new(bdrv_co_em_bh, acb); | ||||
|     acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); | ||||
|     qemu_bh_schedule(acb->bh); | ||||
| } | ||||
|  | ||||
| @@ -4711,7 +4757,7 @@ static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque) | ||||
|     BlockDriverState *bs = acb->common.bs; | ||||
|  | ||||
|     acb->req.error = bdrv_co_flush(bs); | ||||
|     acb->bh = qemu_bh_new(bdrv_co_em_bh, acb); | ||||
|     acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); | ||||
|     qemu_bh_schedule(acb->bh); | ||||
| } | ||||
|  | ||||
| @@ -4738,7 +4784,7 @@ static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque) | ||||
|     BlockDriverState *bs = acb->common.bs; | ||||
|  | ||||
|     acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors); | ||||
|     acb->bh = qemu_bh_new(bdrv_co_em_bh, acb); | ||||
|     acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); | ||||
|     qemu_bh_schedule(acb->bh); | ||||
| } | ||||
|  | ||||
| @@ -4949,7 +4995,11 @@ void bdrv_invalidate_cache_all(Error **errp) | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     QTAILQ_FOREACH(bs, &bdrv_states, device_list) { | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|         aio_context_acquire(aio_context); | ||||
|         bdrv_invalidate_cache(bs, &local_err); | ||||
|         aio_context_release(aio_context); | ||||
|         if (local_err) { | ||||
|             error_propagate(errp, local_err); | ||||
|             return; | ||||
| @@ -4962,7 +5012,11 @@ void bdrv_clear_incoming_migration_all(void) | ||||
|     BlockDriverState *bs; | ||||
|  | ||||
|     QTAILQ_FOREACH(bs, &bdrv_states, device_list) { | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|         aio_context_acquire(aio_context); | ||||
|         bs->open_flags = bs->open_flags & ~(BDRV_O_INCOMING); | ||||
|         aio_context_release(aio_context); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -4978,10 +5032,12 @@ int bdrv_flush(BlockDriverState *bs) | ||||
|         /* Fast-path if already in coroutine context */ | ||||
|         bdrv_flush_co_entry(&rwco); | ||||
|     } else { | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|         co = qemu_coroutine_create(bdrv_flush_co_entry); | ||||
|         qemu_coroutine_enter(co, &rwco); | ||||
|         while (rwco.ret == NOT_DONE) { | ||||
|             qemu_aio_wait(); | ||||
|             aio_poll(aio_context, true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -5091,10 +5147,12 @@ int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) | ||||
|         /* Fast-path if already in coroutine context */ | ||||
|         bdrv_discard_co_entry(&rwco); | ||||
|     } else { | ||||
|         AioContext *aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|         co = qemu_coroutine_create(bdrv_discard_co_entry); | ||||
|         qemu_coroutine_enter(co, &rwco); | ||||
|         while (rwco.ret == NOT_DONE) { | ||||
|             qemu_aio_wait(); | ||||
|             aio_poll(aio_context, true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -5325,15 +5383,74 @@ void bdrv_unref(BlockDriverState *bs) | ||||
|     } | ||||
| } | ||||
|  | ||||
| void bdrv_set_in_use(BlockDriverState *bs, int in_use) | ||||
| struct BdrvOpBlocker { | ||||
|     Error *reason; | ||||
|     QLIST_ENTRY(BdrvOpBlocker) list; | ||||
| }; | ||||
|  | ||||
| bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp) | ||||
| { | ||||
|     assert(bs->in_use != in_use); | ||||
|     bs->in_use = in_use; | ||||
|     BdrvOpBlocker *blocker; | ||||
|     assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); | ||||
|     if (!QLIST_EMPTY(&bs->op_blockers[op])) { | ||||
|         blocker = QLIST_FIRST(&bs->op_blockers[op]); | ||||
|         if (errp) { | ||||
|             error_setg(errp, "Device '%s' is busy: %s", | ||||
|                        bs->device_name, error_get_pretty(blocker->reason)); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| int bdrv_in_use(BlockDriverState *bs) | ||||
| void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason) | ||||
| { | ||||
|     return bs->in_use; | ||||
|     BdrvOpBlocker *blocker; | ||||
|     assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); | ||||
|  | ||||
|     blocker = g_malloc0(sizeof(BdrvOpBlocker)); | ||||
|     blocker->reason = reason; | ||||
|     QLIST_INSERT_HEAD(&bs->op_blockers[op], blocker, list); | ||||
| } | ||||
|  | ||||
| void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason) | ||||
| { | ||||
|     BdrvOpBlocker *blocker, *next; | ||||
|     assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); | ||||
|     QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) { | ||||
|         if (blocker->reason == reason) { | ||||
|             QLIST_REMOVE(blocker, list); | ||||
|             g_free(blocker); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void bdrv_op_block_all(BlockDriverState *bs, Error *reason) | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { | ||||
|         bdrv_op_block(bs, i, reason); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason) | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { | ||||
|         bdrv_op_unblock(bs, i, reason); | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool bdrv_op_blocker_is_empty(BlockDriverState *bs) | ||||
| { | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { | ||||
|         if (!QLIST_EMPTY(&bs->op_blockers[i])) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| void bdrv_iostatus_enable(BlockDriverState *bs) | ||||
| @@ -5546,8 +5663,66 @@ out: | ||||
|  | ||||
| AioContext *bdrv_get_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     /* Currently BlockDriverState always uses the main loop AioContext */ | ||||
|     return qemu_get_aio_context(); | ||||
|     return bs->aio_context; | ||||
| } | ||||
|  | ||||
| void bdrv_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     if (!bs->drv) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (bs->io_limits_enabled) { | ||||
|         throttle_detach_aio_context(&bs->throttle_state); | ||||
|     } | ||||
|     if (bs->drv->bdrv_detach_aio_context) { | ||||
|         bs->drv->bdrv_detach_aio_context(bs); | ||||
|     } | ||||
|     if (bs->file) { | ||||
|         bdrv_detach_aio_context(bs->file); | ||||
|     } | ||||
|     if (bs->backing_hd) { | ||||
|         bdrv_detach_aio_context(bs->backing_hd); | ||||
|     } | ||||
|  | ||||
|     bs->aio_context = NULL; | ||||
| } | ||||
|  | ||||
| void bdrv_attach_aio_context(BlockDriverState *bs, | ||||
|                              AioContext *new_context) | ||||
| { | ||||
|     if (!bs->drv) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     bs->aio_context = new_context; | ||||
|  | ||||
|     if (bs->backing_hd) { | ||||
|         bdrv_attach_aio_context(bs->backing_hd, new_context); | ||||
|     } | ||||
|     if (bs->file) { | ||||
|         bdrv_attach_aio_context(bs->file, new_context); | ||||
|     } | ||||
|     if (bs->drv->bdrv_attach_aio_context) { | ||||
|         bs->drv->bdrv_attach_aio_context(bs, new_context); | ||||
|     } | ||||
|     if (bs->io_limits_enabled) { | ||||
|         throttle_attach_aio_context(&bs->throttle_state, new_context); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) | ||||
| { | ||||
|     bdrv_drain_all(); /* ensure there are no in-flight requests */ | ||||
|  | ||||
|     bdrv_detach_aio_context(bs); | ||||
|  | ||||
|     /* This function executes in the old AioContext so acquire the new one in | ||||
|      * case it runs in a different thread. | ||||
|      */ | ||||
|     aio_context_acquire(new_context); | ||||
|     bdrv_attach_aio_context(bs, new_context); | ||||
|     aio_context_release(new_context); | ||||
| } | ||||
|  | ||||
| void bdrv_add_before_write_notifier(BlockDriverState *bs, | ||||
|   | ||||
| @@ -471,7 +471,7 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs, | ||||
|     acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); | ||||
|     acb->ret = -error; | ||||
|  | ||||
|     bh = qemu_bh_new(error_callback_bh, acb); | ||||
|     bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb); | ||||
|     acb->bh = bh; | ||||
|     qemu_bh_schedule(bh); | ||||
|  | ||||
|   | ||||
| @@ -39,12 +39,13 @@ struct BlkverifyAIOCB { | ||||
| static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb) | ||||
| { | ||||
|     BlkverifyAIOCB *acb = (BlkverifyAIOCB *)blockacb; | ||||
|     AioContext *aio_context = bdrv_get_aio_context(blockacb->bs); | ||||
|     bool finished = false; | ||||
|  | ||||
|     /* Wait until request completes, invokes its callback, and frees itself */ | ||||
|     acb->finished = &finished; | ||||
|     while (!finished) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(aio_context, true); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -228,7 +229,8 @@ static void blkverify_aio_cb(void *opaque, int ret) | ||||
|             acb->verify(acb); | ||||
|         } | ||||
|  | ||||
|         acb->bh = qemu_bh_new(blkverify_aio_bh, acb); | ||||
|         acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs), | ||||
|                              blkverify_aio_bh, acb); | ||||
|         qemu_bh_schedule(acb->bh); | ||||
|         break; | ||||
|     } | ||||
| @@ -302,21 +304,40 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, | ||||
|     return bdrv_recurse_is_first_non_filter(s->test_file, candidate); | ||||
| } | ||||
|  | ||||
| /* Propagate AioContext changes to ->test_file */ | ||||
| static void blkverify_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVBlkverifyState *s = bs->opaque; | ||||
|  | ||||
|     bdrv_detach_aio_context(s->test_file); | ||||
| } | ||||
|  | ||||
| static void blkverify_attach_aio_context(BlockDriverState *bs, | ||||
|                                          AioContext *new_context) | ||||
| { | ||||
|     BDRVBlkverifyState *s = bs->opaque; | ||||
|  | ||||
|     bdrv_attach_aio_context(s->test_file, new_context); | ||||
| } | ||||
|  | ||||
| static BlockDriver bdrv_blkverify = { | ||||
|     .format_name            = "blkverify", | ||||
|     .protocol_name          = "blkverify", | ||||
|     .instance_size          = sizeof(BDRVBlkverifyState), | ||||
|     .format_name                      = "blkverify", | ||||
|     .protocol_name                    = "blkverify", | ||||
|     .instance_size                    = sizeof(BDRVBlkverifyState), | ||||
|  | ||||
|     .bdrv_parse_filename    = blkverify_parse_filename, | ||||
|     .bdrv_file_open         = blkverify_open, | ||||
|     .bdrv_close             = blkverify_close, | ||||
|     .bdrv_getlength         = blkverify_getlength, | ||||
|     .bdrv_parse_filename              = blkverify_parse_filename, | ||||
|     .bdrv_file_open                   = blkverify_open, | ||||
|     .bdrv_close                       = blkverify_close, | ||||
|     .bdrv_getlength                   = blkverify_getlength, | ||||
|  | ||||
|     .bdrv_aio_readv         = blkverify_aio_readv, | ||||
|     .bdrv_aio_writev        = blkverify_aio_writev, | ||||
|     .bdrv_aio_flush         = blkverify_aio_flush, | ||||
|     .bdrv_aio_readv                   = blkverify_aio_readv, | ||||
|     .bdrv_aio_writev                  = blkverify_aio_writev, | ||||
|     .bdrv_aio_flush                   = blkverify_aio_flush, | ||||
|  | ||||
|     .is_filter              = true, | ||||
|     .bdrv_attach_aio_context          = blkverify_attach_aio_context, | ||||
|     .bdrv_detach_aio_context          = blkverify_detach_aio_context, | ||||
|  | ||||
|     .is_filter                        = true, | ||||
|     .bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter, | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										192
									
								
								block/curl.c
									
									
									
									
									
								
							
							
						
						
									
										192
									
								
								block/curl.c
									
									
									
									
									
								
							| @@ -110,6 +110,7 @@ typedef struct BDRVCURLState { | ||||
|     size_t readahead_size; | ||||
|     bool sslverify; | ||||
|     bool accept_range; | ||||
|     AioContext *aio_context; | ||||
| } BDRVCURLState; | ||||
|  | ||||
| static void curl_clean_state(CURLState *s); | ||||
| @@ -134,25 +135,29 @@ static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque) | ||||
| #endif | ||||
|  | ||||
| static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action, | ||||
|                         void *s, void *sp) | ||||
|                         void *userp, void *sp) | ||||
| { | ||||
|     BDRVCURLState *s; | ||||
|     CURLState *state = NULL; | ||||
|     curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state); | ||||
|     state->sock_fd = fd; | ||||
|     s = state->s; | ||||
|  | ||||
|     DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd); | ||||
|     switch (action) { | ||||
|         case CURL_POLL_IN: | ||||
|             qemu_aio_set_fd_handler(fd, curl_multi_read, NULL, state); | ||||
|             aio_set_fd_handler(s->aio_context, fd, curl_multi_read, | ||||
|                                NULL, state); | ||||
|             break; | ||||
|         case CURL_POLL_OUT: | ||||
|             qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, state); | ||||
|             aio_set_fd_handler(s->aio_context, fd, NULL, curl_multi_do, state); | ||||
|             break; | ||||
|         case CURL_POLL_INOUT: | ||||
|             qemu_aio_set_fd_handler(fd, curl_multi_read, curl_multi_do, state); | ||||
|             aio_set_fd_handler(s->aio_context, fd, curl_multi_read, | ||||
|                                curl_multi_do, state); | ||||
|             break; | ||||
|         case CURL_POLL_REMOVE: | ||||
|             qemu_aio_set_fd_handler(fd, NULL, NULL, NULL); | ||||
|             aio_set_fd_handler(s->aio_context, fd, NULL, NULL, NULL); | ||||
|             break; | ||||
|     } | ||||
|  | ||||
| @@ -365,7 +370,7 @@ static CURLState *curl_init_state(BDRVCURLState *s) | ||||
|             break; | ||||
|         } | ||||
|         if (!state) { | ||||
|             qemu_aio_wait(); | ||||
|             aio_poll(state->s->aio_context, true); | ||||
|         } | ||||
|     } while(!state); | ||||
|  | ||||
| @@ -422,6 +427,51 @@ static void curl_parse_filename(const char *filename, QDict *options, | ||||
|     qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename)); | ||||
| } | ||||
|  | ||||
| static void curl_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVCURLState *s = bs->opaque; | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < CURL_NUM_STATES; i++) { | ||||
|         if (s->states[i].in_use) { | ||||
|             curl_clean_state(&s->states[i]); | ||||
|         } | ||||
|         if (s->states[i].curl) { | ||||
|             curl_easy_cleanup(s->states[i].curl); | ||||
|             s->states[i].curl = NULL; | ||||
|         } | ||||
|         if (s->states[i].orig_buf) { | ||||
|             g_free(s->states[i].orig_buf); | ||||
|             s->states[i].orig_buf = NULL; | ||||
|         } | ||||
|     } | ||||
|     if (s->multi) { | ||||
|         curl_multi_cleanup(s->multi); | ||||
|         s->multi = NULL; | ||||
|     } | ||||
|  | ||||
|     timer_del(&s->timer); | ||||
| } | ||||
|  | ||||
| static void curl_attach_aio_context(BlockDriverState *bs, | ||||
|                                     AioContext *new_context) | ||||
| { | ||||
|     BDRVCURLState *s = bs->opaque; | ||||
|  | ||||
|     aio_timer_init(new_context, &s->timer, | ||||
|                    QEMU_CLOCK_REALTIME, SCALE_NS, | ||||
|                    curl_multi_timeout_do, s); | ||||
|  | ||||
|     assert(!s->multi); | ||||
|     s->multi = curl_multi_init(); | ||||
|     s->aio_context = new_context; | ||||
|     curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb); | ||||
| #ifdef NEED_CURL_TIMER_CALLBACK | ||||
|     curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s); | ||||
|     curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static QemuOptsList runtime_opts = { | ||||
|     .name = "curl", | ||||
|     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), | ||||
| @@ -491,6 +541,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     } | ||||
|  | ||||
|     DPRINTF("CURL: Opening %s\n", file); | ||||
|     s->aio_context = bdrv_get_aio_context(bs); | ||||
|     s->url = g_strdup(file); | ||||
|     state = curl_init_state(s); | ||||
|     if (!state) | ||||
| @@ -523,19 +574,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     curl_easy_cleanup(state->curl); | ||||
|     state->curl = NULL; | ||||
|  | ||||
|     aio_timer_init(bdrv_get_aio_context(bs), &s->timer, | ||||
|                    QEMU_CLOCK_REALTIME, SCALE_NS, | ||||
|                    curl_multi_timeout_do, s); | ||||
|  | ||||
|     // Now we know the file exists and its size, so let's | ||||
|     // initialize the multi interface! | ||||
|  | ||||
|     s->multi = curl_multi_init(); | ||||
|     curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb); | ||||
| #ifdef NEED_CURL_TIMER_CALLBACK | ||||
|     curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s); | ||||
|     curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb); | ||||
| #endif | ||||
|     curl_attach_aio_context(bs, bdrv_get_aio_context(bs)); | ||||
|  | ||||
|     qemu_opts_del(opts); | ||||
|     return 0; | ||||
| @@ -630,7 +669,7 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs, | ||||
|     acb->sector_num = sector_num; | ||||
|     acb->nb_sectors = nb_sectors; | ||||
|  | ||||
|     acb->bh = qemu_bh_new(curl_readv_bh_cb, acb); | ||||
|     acb->bh = aio_bh_new(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb); | ||||
|     qemu_bh_schedule(acb->bh); | ||||
|     return &acb->common; | ||||
| } | ||||
| @@ -638,25 +677,9 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs, | ||||
| static void curl_close(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVCURLState *s = bs->opaque; | ||||
|     int i; | ||||
|  | ||||
|     DPRINTF("CURL: Close\n"); | ||||
|     for (i=0; i<CURL_NUM_STATES; i++) { | ||||
|         if (s->states[i].in_use) | ||||
|             curl_clean_state(&s->states[i]); | ||||
|         if (s->states[i].curl) { | ||||
|             curl_easy_cleanup(s->states[i].curl); | ||||
|             s->states[i].curl = NULL; | ||||
|         } | ||||
|         if (s->states[i].orig_buf) { | ||||
|             g_free(s->states[i].orig_buf); | ||||
|             s->states[i].orig_buf = NULL; | ||||
|         } | ||||
|     } | ||||
|     if (s->multi) | ||||
|         curl_multi_cleanup(s->multi); | ||||
|  | ||||
|     timer_del(&s->timer); | ||||
|     curl_detach_aio_context(bs); | ||||
|  | ||||
|     g_free(s->url); | ||||
| } | ||||
| @@ -668,68 +691,83 @@ static int64_t curl_getlength(BlockDriverState *bs) | ||||
| } | ||||
|  | ||||
| static BlockDriver bdrv_http = { | ||||
|     .format_name            = "http", | ||||
|     .protocol_name          = "http", | ||||
|     .format_name                = "http", | ||||
|     .protocol_name              = "http", | ||||
|  | ||||
|     .instance_size          = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename    = curl_parse_filename, | ||||
|     .bdrv_file_open         = curl_open, | ||||
|     .bdrv_close             = curl_close, | ||||
|     .bdrv_getlength         = curl_getlength, | ||||
|     .instance_size              = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename        = curl_parse_filename, | ||||
|     .bdrv_file_open             = curl_open, | ||||
|     .bdrv_close                 = curl_close, | ||||
|     .bdrv_getlength             = curl_getlength, | ||||
|  | ||||
|     .bdrv_aio_readv         = curl_aio_readv, | ||||
|     .bdrv_aio_readv             = curl_aio_readv, | ||||
|  | ||||
|     .bdrv_detach_aio_context    = curl_detach_aio_context, | ||||
|     .bdrv_attach_aio_context    = curl_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static BlockDriver bdrv_https = { | ||||
|     .format_name            = "https", | ||||
|     .protocol_name          = "https", | ||||
|     .format_name                = "https", | ||||
|     .protocol_name              = "https", | ||||
|  | ||||
|     .instance_size          = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename    = curl_parse_filename, | ||||
|     .bdrv_file_open         = curl_open, | ||||
|     .bdrv_close             = curl_close, | ||||
|     .bdrv_getlength         = curl_getlength, | ||||
|     .instance_size              = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename        = curl_parse_filename, | ||||
|     .bdrv_file_open             = curl_open, | ||||
|     .bdrv_close                 = curl_close, | ||||
|     .bdrv_getlength             = curl_getlength, | ||||
|  | ||||
|     .bdrv_aio_readv         = curl_aio_readv, | ||||
|     .bdrv_aio_readv             = curl_aio_readv, | ||||
|  | ||||
|     .bdrv_detach_aio_context    = curl_detach_aio_context, | ||||
|     .bdrv_attach_aio_context    = curl_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static BlockDriver bdrv_ftp = { | ||||
|     .format_name            = "ftp", | ||||
|     .protocol_name          = "ftp", | ||||
|     .format_name                = "ftp", | ||||
|     .protocol_name              = "ftp", | ||||
|  | ||||
|     .instance_size          = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename    = curl_parse_filename, | ||||
|     .bdrv_file_open         = curl_open, | ||||
|     .bdrv_close             = curl_close, | ||||
|     .bdrv_getlength         = curl_getlength, | ||||
|     .instance_size              = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename        = curl_parse_filename, | ||||
|     .bdrv_file_open             = curl_open, | ||||
|     .bdrv_close                 = curl_close, | ||||
|     .bdrv_getlength             = curl_getlength, | ||||
|  | ||||
|     .bdrv_aio_readv         = curl_aio_readv, | ||||
|     .bdrv_aio_readv             = curl_aio_readv, | ||||
|  | ||||
|     .bdrv_detach_aio_context    = curl_detach_aio_context, | ||||
|     .bdrv_attach_aio_context    = curl_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static BlockDriver bdrv_ftps = { | ||||
|     .format_name            = "ftps", | ||||
|     .protocol_name          = "ftps", | ||||
|     .format_name                = "ftps", | ||||
|     .protocol_name              = "ftps", | ||||
|  | ||||
|     .instance_size          = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename    = curl_parse_filename, | ||||
|     .bdrv_file_open         = curl_open, | ||||
|     .bdrv_close             = curl_close, | ||||
|     .bdrv_getlength         = curl_getlength, | ||||
|     .instance_size              = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename        = curl_parse_filename, | ||||
|     .bdrv_file_open             = curl_open, | ||||
|     .bdrv_close                 = curl_close, | ||||
|     .bdrv_getlength             = curl_getlength, | ||||
|  | ||||
|     .bdrv_aio_readv         = curl_aio_readv, | ||||
|     .bdrv_aio_readv             = curl_aio_readv, | ||||
|  | ||||
|     .bdrv_detach_aio_context    = curl_detach_aio_context, | ||||
|     .bdrv_attach_aio_context    = curl_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static BlockDriver bdrv_tftp = { | ||||
|     .format_name            = "tftp", | ||||
|     .protocol_name          = "tftp", | ||||
|     .format_name                = "tftp", | ||||
|     .protocol_name              = "tftp", | ||||
|  | ||||
|     .instance_size          = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename    = curl_parse_filename, | ||||
|     .bdrv_file_open         = curl_open, | ||||
|     .bdrv_close             = curl_close, | ||||
|     .bdrv_getlength         = curl_getlength, | ||||
|     .instance_size              = sizeof(BDRVCURLState), | ||||
|     .bdrv_parse_filename        = curl_parse_filename, | ||||
|     .bdrv_file_open             = curl_open, | ||||
|     .bdrv_close                 = curl_close, | ||||
|     .bdrv_getlength             = curl_getlength, | ||||
|  | ||||
|     .bdrv_aio_readv         = curl_aio_readv, | ||||
|     .bdrv_aio_readv             = curl_aio_readv, | ||||
|  | ||||
|     .bdrv_detach_aio_context    = curl_detach_aio_context, | ||||
|     .bdrv_attach_aio_context    = curl_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static void curl_block_init(void) | ||||
|   | ||||
| @@ -16,6 +16,7 @@ typedef struct GlusterAIOCB { | ||||
|     int ret; | ||||
|     QEMUBH *bh; | ||||
|     Coroutine *coroutine; | ||||
|     AioContext *aio_context; | ||||
| } GlusterAIOCB; | ||||
|  | ||||
| typedef struct BDRVGlusterState { | ||||
| @@ -249,7 +250,7 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg) | ||||
|         acb->ret = -EIO; /* Partial read/write - fail it */ | ||||
|     } | ||||
|  | ||||
|     acb->bh = qemu_bh_new(qemu_gluster_complete_aio, acb); | ||||
|     acb->bh = aio_bh_new(acb->aio_context, qemu_gluster_complete_aio, acb); | ||||
|     qemu_bh_schedule(acb->bh); | ||||
| } | ||||
|  | ||||
| @@ -436,6 +437,7 @@ static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs, | ||||
|     acb->size = size; | ||||
|     acb->ret = 0; | ||||
|     acb->coroutine = qemu_coroutine_self(); | ||||
|     acb->aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|     ret = glfs_zerofill_async(s->fd, offset, size, &gluster_finish_aiocb, acb); | ||||
|     if (ret < 0) { | ||||
| @@ -549,6 +551,7 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs, | ||||
|     acb->size = size; | ||||
|     acb->ret = 0; | ||||
|     acb->coroutine = qemu_coroutine_self(); | ||||
|     acb->aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|     if (write) { | ||||
|         ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0, | ||||
| @@ -605,6 +608,7 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs) | ||||
|     acb->size = 0; | ||||
|     acb->ret = 0; | ||||
|     acb->coroutine = qemu_coroutine_self(); | ||||
|     acb->aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|     ret = glfs_fsync_async(s->fd, &gluster_finish_aiocb, acb); | ||||
|     if (ret < 0) { | ||||
| @@ -633,6 +637,7 @@ static coroutine_fn int qemu_gluster_co_discard(BlockDriverState *bs, | ||||
|     acb->size = 0; | ||||
|     acb->ret = 0; | ||||
|     acb->coroutine = qemu_coroutine_self(); | ||||
|     acb->aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|     ret = glfs_discard_async(s->fd, offset, size, &gluster_finish_aiocb, acb); | ||||
|     if (ret < 0) { | ||||
|   | ||||
| @@ -49,6 +49,7 @@ | ||||
|  | ||||
| typedef struct IscsiLun { | ||||
|     struct iscsi_context *iscsi; | ||||
|     AioContext *aio_context; | ||||
|     int lun; | ||||
|     enum scsi_inquiry_peripheral_device_type type; | ||||
|     int block_size; | ||||
| @@ -73,6 +74,7 @@ typedef struct IscsiTask { | ||||
|     struct scsi_task *task; | ||||
|     Coroutine *co; | ||||
|     QEMUBH *bh; | ||||
|     IscsiLun *iscsilun; | ||||
| } IscsiTask; | ||||
|  | ||||
| typedef struct IscsiAIOCB { | ||||
| @@ -133,7 +135,7 @@ iscsi_schedule_bh(IscsiAIOCB *acb) | ||||
|     if (acb->bh) { | ||||
|         return; | ||||
|     } | ||||
|     acb->bh = qemu_bh_new(iscsi_bh_cb, acb); | ||||
|     acb->bh = aio_bh_new(acb->iscsilun->aio_context, iscsi_bh_cb, acb); | ||||
|     qemu_bh_schedule(acb->bh); | ||||
| } | ||||
|  | ||||
| @@ -169,7 +171,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, | ||||
|  | ||||
| out: | ||||
|     if (iTask->co) { | ||||
|         iTask->bh = qemu_bh_new(iscsi_co_generic_bh_cb, iTask); | ||||
|         iTask->bh = aio_bh_new(iTask->iscsilun->aio_context, | ||||
|                                iscsi_co_generic_bh_cb, iTask); | ||||
|         qemu_bh_schedule(iTask->bh); | ||||
|     } | ||||
| } | ||||
| @@ -177,8 +180,9 @@ out: | ||||
| static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) | ||||
| { | ||||
|     *iTask = (struct IscsiTask) { | ||||
|         .co         = qemu_coroutine_self(), | ||||
|         .retries    = ISCSI_CMD_RETRIES, | ||||
|         .co             = qemu_coroutine_self(), | ||||
|         .retries        = ISCSI_CMD_RETRIES, | ||||
|         .iscsilun       = iscsilun, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @@ -209,7 +213,7 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb) | ||||
|                                      iscsi_abort_task_cb, acb); | ||||
|  | ||||
|     while (acb->status == -EINPROGRESS) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(iscsilun->aio_context, true); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -232,10 +236,11 @@ iscsi_set_events(IscsiLun *iscsilun) | ||||
|     ev = POLLIN; | ||||
|     ev |= iscsi_which_events(iscsi); | ||||
|     if (ev != iscsilun->events) { | ||||
|         qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), | ||||
|                       iscsi_process_read, | ||||
|                       (ev & POLLOUT) ? iscsi_process_write : NULL, | ||||
|                       iscsilun); | ||||
|         aio_set_fd_handler(iscsilun->aio_context, | ||||
|                            iscsi_get_fd(iscsi), | ||||
|                            iscsi_process_read, | ||||
|                            (ev & POLLOUT) ? iscsi_process_write : NULL, | ||||
|                            iscsilun); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -791,7 +796,7 @@ static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) | ||||
|         iscsi_aio_ioctl(bs, req, buf, ioctl_cb, &status); | ||||
|  | ||||
|         while (status == -EINPROGRESS) { | ||||
|             qemu_aio_wait(); | ||||
|             aio_poll(iscsilun->aio_context, true); | ||||
|         } | ||||
|  | ||||
|         return 0; | ||||
| @@ -1195,6 +1200,40 @@ fail_with_err: | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| static void iscsi_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     IscsiLun *iscsilun = bs->opaque; | ||||
|  | ||||
|     aio_set_fd_handler(iscsilun->aio_context, | ||||
|                        iscsi_get_fd(iscsilun->iscsi), | ||||
|                        NULL, NULL, NULL); | ||||
|     iscsilun->events = 0; | ||||
|  | ||||
|     if (iscsilun->nop_timer) { | ||||
|         timer_del(iscsilun->nop_timer); | ||||
|         timer_free(iscsilun->nop_timer); | ||||
|         iscsilun->nop_timer = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void iscsi_attach_aio_context(BlockDriverState *bs, | ||||
|                                      AioContext *new_context) | ||||
| { | ||||
|     IscsiLun *iscsilun = bs->opaque; | ||||
|  | ||||
|     iscsilun->aio_context = new_context; | ||||
|     iscsi_set_events(iscsilun); | ||||
|  | ||||
| #if defined(LIBISCSI_FEATURE_NOP_COUNTER) | ||||
|     /* Set up a timer for sending out iSCSI NOPs */ | ||||
|     iscsilun->nop_timer = aio_timer_new(iscsilun->aio_context, | ||||
|                                         QEMU_CLOCK_REALTIME, SCALE_MS, | ||||
|                                         iscsi_nop_timed_event, iscsilun); | ||||
|     timer_mod(iscsilun->nop_timer, | ||||
|               qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * We support iscsi url's on the form | ||||
|  * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun> | ||||
| @@ -1301,6 +1340,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     } | ||||
|  | ||||
|     iscsilun->iscsi = iscsi; | ||||
|     iscsilun->aio_context = bdrv_get_aio_context(bs); | ||||
|     iscsilun->lun   = iscsi_url->lun; | ||||
|     iscsilun->has_write_same = true; | ||||
|  | ||||
| @@ -1374,11 +1414,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     scsi_free_scsi_task(task); | ||||
|     task = NULL; | ||||
|  | ||||
| #if defined(LIBISCSI_FEATURE_NOP_COUNTER) | ||||
|     /* Set up a timer for sending out iSCSI NOPs */ | ||||
|     iscsilun->nop_timer = timer_new_ms(QEMU_CLOCK_REALTIME, iscsi_nop_timed_event, iscsilun); | ||||
|     timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); | ||||
| #endif | ||||
|     iscsi_attach_aio_context(bs, iscsilun->aio_context); | ||||
|  | ||||
|     /* Guess the internal cluster (page) size of the iscsi target by the means | ||||
|      * of opt_unmap_gran. Transfer the unmap granularity only if it has a | ||||
| @@ -1422,11 +1458,7 @@ static void iscsi_close(BlockDriverState *bs) | ||||
|     IscsiLun *iscsilun = bs->opaque; | ||||
|     struct iscsi_context *iscsi = iscsilun->iscsi; | ||||
|  | ||||
|     if (iscsilun->nop_timer) { | ||||
|         timer_del(iscsilun->nop_timer); | ||||
|         timer_free(iscsilun->nop_timer); | ||||
|     } | ||||
|     qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL); | ||||
|     iscsi_detach_aio_context(bs); | ||||
|     iscsi_destroy_context(iscsi); | ||||
|     g_free(iscsilun->zeroblock); | ||||
|     g_free(iscsilun->allocationmap); | ||||
| @@ -1530,10 +1562,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options, | ||||
|     if (ret != 0) { | ||||
|         goto out; | ||||
|     } | ||||
|     if (iscsilun->nop_timer) { | ||||
|         timer_del(iscsilun->nop_timer); | ||||
|         timer_free(iscsilun->nop_timer); | ||||
|     } | ||||
|     iscsi_detach_aio_context(bs); | ||||
|     if (iscsilun->type != TYPE_DISK) { | ||||
|         ret = -ENODEV; | ||||
|         goto out; | ||||
| @@ -1604,6 +1633,9 @@ static BlockDriver bdrv_iscsi = { | ||||
|     .bdrv_ioctl       = iscsi_ioctl, | ||||
|     .bdrv_aio_ioctl   = iscsi_aio_ioctl, | ||||
| #endif | ||||
|  | ||||
|     .bdrv_detach_aio_context = iscsi_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = iscsi_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static QemuOptsList qemu_iscsi_opts = { | ||||
|   | ||||
| @@ -177,6 +177,20 @@ out_free_aiocb: | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| void laio_detach_aio_context(void *s_, AioContext *old_context) | ||||
| { | ||||
|     struct qemu_laio_state *s = s_; | ||||
|  | ||||
|     aio_set_event_notifier(old_context, &s->e, NULL); | ||||
| } | ||||
|  | ||||
| void laio_attach_aio_context(void *s_, AioContext *new_context) | ||||
| { | ||||
|     struct qemu_laio_state *s = s_; | ||||
|  | ||||
|     aio_set_event_notifier(new_context, &s->e, qemu_laio_completion_cb); | ||||
| } | ||||
|  | ||||
| void *laio_init(void) | ||||
| { | ||||
|     struct qemu_laio_state *s; | ||||
| @@ -190,8 +204,6 @@ void *laio_init(void) | ||||
|         goto out_close_efd; | ||||
|     } | ||||
|  | ||||
|     qemu_aio_set_event_notifier(&s->e, qemu_laio_completion_cb); | ||||
|  | ||||
|     return s; | ||||
|  | ||||
| out_close_efd: | ||||
| @@ -200,3 +212,11 @@ out_free_state: | ||||
|     g_free(s); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| void laio_cleanup(void *s_) | ||||
| { | ||||
|     struct qemu_laio_state *s = s_; | ||||
|  | ||||
|     event_notifier_cleanup(&s->e); | ||||
|     g_free(s); | ||||
| } | ||||
|   | ||||
| @@ -498,7 +498,7 @@ immediate_exit: | ||||
|             /* drop the bs loop chain formed by the swap: break the loop then | ||||
|              * trigger the unref from the top one */ | ||||
|             BlockDriverState *p = s->base->backing_hd; | ||||
|             s->base->backing_hd = NULL; | ||||
|             bdrv_set_backing_hd(s->base, NULL); | ||||
|             bdrv_unref(p); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -49,7 +49,7 @@ static void nbd_teardown_connection(NbdClientSession *client) | ||||
|     shutdown(client->sock, 2); | ||||
|     nbd_recv_coroutines_enter_all(client); | ||||
|  | ||||
|     qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL); | ||||
|     nbd_client_session_detach_aio_context(client); | ||||
|     closesocket(client->sock); | ||||
|     client->sock = -1; | ||||
| } | ||||
| @@ -103,11 +103,14 @@ static int nbd_co_send_request(NbdClientSession *s, | ||||
|     struct nbd_request *request, | ||||
|     QEMUIOVector *qiov, int offset) | ||||
| { | ||||
|     AioContext *aio_context; | ||||
|     int rc, ret; | ||||
|  | ||||
|     qemu_co_mutex_lock(&s->send_mutex); | ||||
|     s->send_coroutine = qemu_coroutine_self(); | ||||
|     qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write, s); | ||||
|     aio_context = bdrv_get_aio_context(s->bs); | ||||
|     aio_set_fd_handler(aio_context, s->sock, | ||||
|                        nbd_reply_ready, nbd_restart_write, s); | ||||
|     if (qiov) { | ||||
|         if (!s->is_unix) { | ||||
|             socket_set_cork(s->sock, 1); | ||||
| @@ -126,7 +129,7 @@ static int nbd_co_send_request(NbdClientSession *s, | ||||
|     } else { | ||||
|         rc = nbd_send_request(s->sock, request); | ||||
|     } | ||||
|     qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL, s); | ||||
|     aio_set_fd_handler(aio_context, s->sock, nbd_reply_ready, NULL, s); | ||||
|     s->send_coroutine = NULL; | ||||
|     qemu_co_mutex_unlock(&s->send_mutex); | ||||
|     return rc; | ||||
| @@ -335,6 +338,19 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num, | ||||
|  | ||||
| } | ||||
|  | ||||
| void nbd_client_session_detach_aio_context(NbdClientSession *client) | ||||
| { | ||||
|     aio_set_fd_handler(bdrv_get_aio_context(client->bs), client->sock, | ||||
|                        NULL, NULL, NULL); | ||||
| } | ||||
|  | ||||
| void nbd_client_session_attach_aio_context(NbdClientSession *client, | ||||
|                                            AioContext *new_context) | ||||
| { | ||||
|     aio_set_fd_handler(new_context, client->sock, | ||||
|                        nbd_reply_ready, NULL, client); | ||||
| } | ||||
|  | ||||
| void nbd_client_session_close(NbdClientSession *client) | ||||
| { | ||||
|     struct nbd_request request = { | ||||
| @@ -381,7 +397,7 @@ int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs, | ||||
|     /* Now that we're connected, set the socket to be non-blocking and | ||||
|      * kick the reply mechanism.  */ | ||||
|     qemu_set_nonblock(sock); | ||||
|     qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL, client); | ||||
|     nbd_client_session_attach_aio_context(client, bdrv_get_aio_context(bs)); | ||||
|  | ||||
|     logout("Established connection with NBD server\n"); | ||||
|     return 0; | ||||
|   | ||||
| @@ -47,4 +47,8 @@ int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num, | ||||
| int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num, | ||||
|                                 int nb_sectors, QEMUIOVector *qiov); | ||||
|  | ||||
| void nbd_client_session_detach_aio_context(NbdClientSession *client); | ||||
| void nbd_client_session_attach_aio_context(NbdClientSession *client, | ||||
|                                            AioContext *new_context); | ||||
|  | ||||
| #endif /* NBD_CLIENT_H */ | ||||
|   | ||||
							
								
								
									
										87
									
								
								block/nbd.c
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								block/nbd.c
									
									
									
									
									
								
							| @@ -323,46 +323,67 @@ static int64_t nbd_getlength(BlockDriverState *bs) | ||||
|     return s->client.size; | ||||
| } | ||||
|  | ||||
| static void nbd_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVNBDState *s = bs->opaque; | ||||
|  | ||||
|     nbd_client_session_detach_aio_context(&s->client); | ||||
| } | ||||
|  | ||||
| static void nbd_attach_aio_context(BlockDriverState *bs, | ||||
|                                    AioContext *new_context) | ||||
| { | ||||
|     BDRVNBDState *s = bs->opaque; | ||||
|  | ||||
|     nbd_client_session_attach_aio_context(&s->client, new_context); | ||||
| } | ||||
|  | ||||
| static BlockDriver bdrv_nbd = { | ||||
|     .format_name         = "nbd", | ||||
|     .protocol_name       = "nbd", | ||||
|     .instance_size       = sizeof(BDRVNBDState), | ||||
|     .bdrv_parse_filename = nbd_parse_filename, | ||||
|     .bdrv_file_open      = nbd_open, | ||||
|     .bdrv_co_readv       = nbd_co_readv, | ||||
|     .bdrv_co_writev      = nbd_co_writev, | ||||
|     .bdrv_close          = nbd_close, | ||||
|     .bdrv_co_flush_to_os = nbd_co_flush, | ||||
|     .bdrv_co_discard     = nbd_co_discard, | ||||
|     .bdrv_getlength      = nbd_getlength, | ||||
|     .format_name                = "nbd", | ||||
|     .protocol_name              = "nbd", | ||||
|     .instance_size              = sizeof(BDRVNBDState), | ||||
|     .bdrv_parse_filename        = nbd_parse_filename, | ||||
|     .bdrv_file_open             = nbd_open, | ||||
|     .bdrv_co_readv              = nbd_co_readv, | ||||
|     .bdrv_co_writev             = nbd_co_writev, | ||||
|     .bdrv_close                 = nbd_close, | ||||
|     .bdrv_co_flush_to_os        = nbd_co_flush, | ||||
|     .bdrv_co_discard            = nbd_co_discard, | ||||
|     .bdrv_getlength             = nbd_getlength, | ||||
|     .bdrv_detach_aio_context    = nbd_detach_aio_context, | ||||
|     .bdrv_attach_aio_context    = nbd_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static BlockDriver bdrv_nbd_tcp = { | ||||
|     .format_name         = "nbd", | ||||
|     .protocol_name       = "nbd+tcp", | ||||
|     .instance_size       = sizeof(BDRVNBDState), | ||||
|     .bdrv_parse_filename = nbd_parse_filename, | ||||
|     .bdrv_file_open      = nbd_open, | ||||
|     .bdrv_co_readv       = nbd_co_readv, | ||||
|     .bdrv_co_writev      = nbd_co_writev, | ||||
|     .bdrv_close          = nbd_close, | ||||
|     .bdrv_co_flush_to_os = nbd_co_flush, | ||||
|     .bdrv_co_discard     = nbd_co_discard, | ||||
|     .bdrv_getlength      = nbd_getlength, | ||||
|     .format_name                = "nbd", | ||||
|     .protocol_name              = "nbd+tcp", | ||||
|     .instance_size              = sizeof(BDRVNBDState), | ||||
|     .bdrv_parse_filename        = nbd_parse_filename, | ||||
|     .bdrv_file_open             = nbd_open, | ||||
|     .bdrv_co_readv              = nbd_co_readv, | ||||
|     .bdrv_co_writev             = nbd_co_writev, | ||||
|     .bdrv_close                 = nbd_close, | ||||
|     .bdrv_co_flush_to_os        = nbd_co_flush, | ||||
|     .bdrv_co_discard            = nbd_co_discard, | ||||
|     .bdrv_getlength             = nbd_getlength, | ||||
|     .bdrv_detach_aio_context    = nbd_detach_aio_context, | ||||
|     .bdrv_attach_aio_context    = nbd_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static BlockDriver bdrv_nbd_unix = { | ||||
|     .format_name         = "nbd", | ||||
|     .protocol_name       = "nbd+unix", | ||||
|     .instance_size       = sizeof(BDRVNBDState), | ||||
|     .bdrv_parse_filename = nbd_parse_filename, | ||||
|     .bdrv_file_open      = nbd_open, | ||||
|     .bdrv_co_readv       = nbd_co_readv, | ||||
|     .bdrv_co_writev      = nbd_co_writev, | ||||
|     .bdrv_close          = nbd_close, | ||||
|     .bdrv_co_flush_to_os = nbd_co_flush, | ||||
|     .bdrv_co_discard     = nbd_co_discard, | ||||
|     .bdrv_getlength      = nbd_getlength, | ||||
|     .format_name                = "nbd", | ||||
|     .protocol_name              = "nbd+unix", | ||||
|     .instance_size              = sizeof(BDRVNBDState), | ||||
|     .bdrv_parse_filename        = nbd_parse_filename, | ||||
|     .bdrv_file_open             = nbd_open, | ||||
|     .bdrv_co_readv              = nbd_co_readv, | ||||
|     .bdrv_co_writev             = nbd_co_writev, | ||||
|     .bdrv_close                 = nbd_close, | ||||
|     .bdrv_co_flush_to_os        = nbd_co_flush, | ||||
|     .bdrv_co_discard            = nbd_co_discard, | ||||
|     .bdrv_getlength             = nbd_getlength, | ||||
|     .bdrv_detach_aio_context    = nbd_detach_aio_context, | ||||
|     .bdrv_attach_aio_context    = nbd_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static void bdrv_nbd_init(void) | ||||
|   | ||||
							
								
								
									
										75
									
								
								block/nfs.c
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								block/nfs.c
									
									
									
									
									
								
							| @@ -40,6 +40,7 @@ typedef struct NFSClient { | ||||
|     struct nfsfh *fh; | ||||
|     int events; | ||||
|     bool has_zero_init; | ||||
|     AioContext *aio_context; | ||||
| } NFSClient; | ||||
|  | ||||
| typedef struct NFSRPC { | ||||
| @@ -49,6 +50,7 @@ typedef struct NFSRPC { | ||||
|     struct stat *st; | ||||
|     Coroutine *co; | ||||
|     QEMUBH *bh; | ||||
|     NFSClient *client; | ||||
| } NFSRPC; | ||||
|  | ||||
| static void nfs_process_read(void *arg); | ||||
| @@ -58,10 +60,11 @@ static void nfs_set_events(NFSClient *client) | ||||
| { | ||||
|     int ev = nfs_which_events(client->context); | ||||
|     if (ev != client->events) { | ||||
|         qemu_aio_set_fd_handler(nfs_get_fd(client->context), | ||||
|                       (ev & POLLIN) ? nfs_process_read : NULL, | ||||
|                       (ev & POLLOUT) ? nfs_process_write : NULL, | ||||
|                       client); | ||||
|         aio_set_fd_handler(client->aio_context, | ||||
|                            nfs_get_fd(client->context), | ||||
|                            (ev & POLLIN) ? nfs_process_read : NULL, | ||||
|                            (ev & POLLOUT) ? nfs_process_write : NULL, | ||||
|                            client); | ||||
|  | ||||
|     } | ||||
|     client->events = ev; | ||||
| @@ -84,7 +87,8 @@ static void nfs_process_write(void *arg) | ||||
| static void nfs_co_init_task(NFSClient *client, NFSRPC *task) | ||||
| { | ||||
|     *task = (NFSRPC) { | ||||
|         .co         = qemu_coroutine_self(), | ||||
|         .co             = qemu_coroutine_self(), | ||||
|         .client         = client, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @@ -116,7 +120,8 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data, | ||||
|         error_report("NFS Error: %s", nfs_get_error(nfs)); | ||||
|     } | ||||
|     if (task->co) { | ||||
|         task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task); | ||||
|         task->bh = aio_bh_new(task->client->aio_context, | ||||
|                               nfs_co_generic_bh_cb, task); | ||||
|         qemu_bh_schedule(task->bh); | ||||
|     } | ||||
| } | ||||
| @@ -224,13 +229,34 @@ static QemuOptsList runtime_opts = { | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| static void nfs_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     NFSClient *client = bs->opaque; | ||||
|  | ||||
|     aio_set_fd_handler(client->aio_context, | ||||
|                        nfs_get_fd(client->context), | ||||
|                        NULL, NULL, NULL); | ||||
|     client->events = 0; | ||||
| } | ||||
|  | ||||
| static void nfs_attach_aio_context(BlockDriverState *bs, | ||||
|                                    AioContext *new_context) | ||||
| { | ||||
|     NFSClient *client = bs->opaque; | ||||
|  | ||||
|     client->aio_context = new_context; | ||||
|     nfs_set_events(client); | ||||
| } | ||||
|  | ||||
| static void nfs_client_close(NFSClient *client) | ||||
| { | ||||
|     if (client->context) { | ||||
|         if (client->fh) { | ||||
|             nfs_close(client->context, client->fh); | ||||
|         } | ||||
|         qemu_aio_set_fd_handler(nfs_get_fd(client->context), NULL, NULL, NULL); | ||||
|         aio_set_fd_handler(client->aio_context, | ||||
|                            nfs_get_fd(client->context), | ||||
|                            NULL, NULL, NULL); | ||||
|         nfs_destroy_context(client->context); | ||||
|     } | ||||
|     memset(client, 0, sizeof(NFSClient)); | ||||
| @@ -345,6 +371,8 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     QemuOpts *opts; | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     client->aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); | ||||
|     qemu_opts_absorb_qdict(opts, options, &local_err); | ||||
|     if (local_err) { | ||||
| @@ -368,6 +396,8 @@ static int nfs_file_create(const char *url, QEMUOptionParameter *options, | ||||
|     int64_t total_size = 0; | ||||
|     NFSClient *client = g_malloc0(sizeof(NFSClient)); | ||||
|  | ||||
|     client->aio_context = qemu_get_aio_context(); | ||||
|  | ||||
|     /* Read out options */ | ||||
|     while (options && options->name) { | ||||
|         if (!strcmp(options->name, "size")) { | ||||
| @@ -407,7 +437,7 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) | ||||
|  | ||||
|     while (!task.complete) { | ||||
|         nfs_set_events(client); | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(client->aio_context, true); | ||||
|     } | ||||
|  | ||||
|     return (task.ret < 0 ? task.ret : st.st_blocks * st.st_blksize); | ||||
| @@ -420,22 +450,25 @@ static int nfs_file_truncate(BlockDriverState *bs, int64_t offset) | ||||
| } | ||||
|  | ||||
| static BlockDriver bdrv_nfs = { | ||||
|     .format_name     = "nfs", | ||||
|     .protocol_name   = "nfs", | ||||
|     .format_name                    = "nfs", | ||||
|     .protocol_name                  = "nfs", | ||||
|  | ||||
|     .instance_size   = sizeof(NFSClient), | ||||
|     .bdrv_needs_filename = true, | ||||
|     .bdrv_has_zero_init = nfs_has_zero_init, | ||||
|     .bdrv_get_allocated_file_size = nfs_get_allocated_file_size, | ||||
|     .bdrv_truncate = nfs_file_truncate, | ||||
|     .instance_size                  = sizeof(NFSClient), | ||||
|     .bdrv_needs_filename            = true, | ||||
|     .bdrv_has_zero_init             = nfs_has_zero_init, | ||||
|     .bdrv_get_allocated_file_size   = nfs_get_allocated_file_size, | ||||
|     .bdrv_truncate                  = nfs_file_truncate, | ||||
|  | ||||
|     .bdrv_file_open  = nfs_file_open, | ||||
|     .bdrv_close      = nfs_file_close, | ||||
|     .bdrv_create     = nfs_file_create, | ||||
|     .bdrv_file_open                 = nfs_file_open, | ||||
|     .bdrv_close                     = nfs_file_close, | ||||
|     .bdrv_create                    = nfs_file_create, | ||||
|  | ||||
|     .bdrv_co_readv         = nfs_co_readv, | ||||
|     .bdrv_co_writev        = nfs_co_writev, | ||||
|     .bdrv_co_flush_to_disk = nfs_co_flush, | ||||
|     .bdrv_co_readv                  = nfs_co_readv, | ||||
|     .bdrv_co_writev                 = nfs_co_writev, | ||||
|     .bdrv_co_flush_to_disk          = nfs_co_flush, | ||||
|  | ||||
|     .bdrv_detach_aio_context        = nfs_detach_aio_context, | ||||
|     .bdrv_attach_aio_context        = nfs_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static void nfs_block_init(void) | ||||
|   | ||||
| @@ -475,6 +475,7 @@ static void dump_qobject(fprintf_function func_fprintf, void *f, | ||||
|         case QTYPE_QERROR: { | ||||
|             QString *value = qerror_human((QError *)obj); | ||||
|             func_fprintf(f, "%s", qstring_get_str(value)); | ||||
|             QDECREF(value); | ||||
|             break; | ||||
|         } | ||||
|         case QTYPE_NONE: | ||||
|   | ||||
| @@ -379,7 +379,8 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs, | ||||
|     BLKDBG_EVENT(bs->file, BLKDBG_COW_READ); | ||||
|  | ||||
|     if (!bs->drv) { | ||||
|         return -ENOMEDIUM; | ||||
|         ret = -ENOMEDIUM; | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     /* Call .bdrv_co_readv() directly instead of using the public block-layer | ||||
|   | ||||
| @@ -1308,6 +1308,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) | ||||
|     options = qdict_clone_shallow(bs->options); | ||||
|  | ||||
|     ret = qcow2_open(bs, options, flags, &local_err); | ||||
|     QDECREF(options); | ||||
|     if (local_err) { | ||||
|         error_setg(errp, "Could not reopen qcow2 layer: %s", | ||||
|                    error_get_pretty(local_err)); | ||||
| @@ -1318,8 +1319,6 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     QDECREF(options); | ||||
|  | ||||
|     if (crypt_method) { | ||||
|         s->crypt_method = crypt_method; | ||||
|         memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key)); | ||||
|   | ||||
| @@ -173,7 +173,7 @@ int qed_read_l1_table_sync(BDRVQEDState *s) | ||||
|     qed_read_table(s, s->header.l1_table_offset, | ||||
|                    s->l1_table, qed_sync_cb, &ret); | ||||
|     while (ret == -EINPROGRESS) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(bdrv_get_aio_context(s->bs), true); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| @@ -194,7 +194,7 @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index, | ||||
|  | ||||
|     qed_write_l1_table(s, index, n, qed_sync_cb, &ret); | ||||
|     while (ret == -EINPROGRESS) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(bdrv_get_aio_context(s->bs), true); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| @@ -267,7 +267,7 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset | ||||
|  | ||||
|     qed_read_l2_table(s, request, offset, qed_sync_cb, &ret); | ||||
|     while (ret == -EINPROGRESS) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(bdrv_get_aio_context(s->bs), true); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| @@ -289,7 +289,7 @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request, | ||||
|  | ||||
|     qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret); | ||||
|     while (ret == -EINPROGRESS) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(bdrv_get_aio_context(s->bs), true); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
|   | ||||
							
								
								
									
										35
									
								
								block/qed.c
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								block/qed.c
									
									
									
									
									
								
							| @@ -21,12 +21,13 @@ | ||||
| static void qed_aio_cancel(BlockDriverAIOCB *blockacb) | ||||
| { | ||||
|     QEDAIOCB *acb = (QEDAIOCB *)blockacb; | ||||
|     AioContext *aio_context = bdrv_get_aio_context(blockacb->bs); | ||||
|     bool finished = false; | ||||
|  | ||||
|     /* Wait for the request to finish */ | ||||
|     acb->finished = &finished; | ||||
|     while (!finished) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(aio_context, true); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -373,6 +374,27 @@ static void bdrv_qed_rebind(BlockDriverState *bs) | ||||
|     s->bs = bs; | ||||
| } | ||||
|  | ||||
| static void bdrv_qed_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVQEDState *s = bs->opaque; | ||||
|  | ||||
|     qed_cancel_need_check_timer(s); | ||||
|     timer_free(s->need_check_timer); | ||||
| } | ||||
|  | ||||
| static void bdrv_qed_attach_aio_context(BlockDriverState *bs, | ||||
|                                         AioContext *new_context) | ||||
| { | ||||
|     BDRVQEDState *s = bs->opaque; | ||||
|  | ||||
|     s->need_check_timer = aio_timer_new(new_context, | ||||
|                                         QEMU_CLOCK_VIRTUAL, SCALE_NS, | ||||
|                                         qed_need_check_timer_cb, s); | ||||
|     if (s->header.features & QED_F_NEED_CHECK) { | ||||
|         qed_start_need_check_timer(s); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|                          Error **errp) | ||||
| { | ||||
| @@ -496,8 +518,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, | ||||
|                                             qed_need_check_timer_cb, s); | ||||
|     bdrv_qed_attach_aio_context(bs, bdrv_get_aio_context(bs)); | ||||
|  | ||||
| out: | ||||
|     if (ret) { | ||||
| @@ -528,8 +549,7 @@ static void bdrv_qed_close(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVQEDState *s = bs->opaque; | ||||
|  | ||||
|     qed_cancel_need_check_timer(s); | ||||
|     timer_free(s->need_check_timer); | ||||
|     bdrv_qed_detach_aio_context(bs); | ||||
|  | ||||
|     /* Ensure writes reach stable storage */ | ||||
|     bdrv_flush(bs->file); | ||||
| @@ -919,7 +939,8 @@ static void qed_aio_complete(QEDAIOCB *acb, int ret) | ||||
|  | ||||
|     /* Arrange for a bh to invoke the completion function */ | ||||
|     acb->bh_ret = ret; | ||||
|     acb->bh = qemu_bh_new(qed_aio_complete_bh, acb); | ||||
|     acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs), | ||||
|                          qed_aio_complete_bh, acb); | ||||
|     qemu_bh_schedule(acb->bh); | ||||
|  | ||||
|     /* Start next allocating write request waiting behind this one.  Note that | ||||
| @@ -1644,6 +1665,8 @@ static BlockDriver bdrv_qed = { | ||||
|     .bdrv_change_backing_file = bdrv_qed_change_backing_file, | ||||
|     .bdrv_invalidate_cache    = bdrv_qed_invalidate_cache, | ||||
|     .bdrv_check               = bdrv_qed_check, | ||||
|     .bdrv_detach_aio_context  = bdrv_qed_detach_aio_context, | ||||
|     .bdrv_attach_aio_context  = bdrv_qed_attach_aio_context, | ||||
| }; | ||||
|  | ||||
| static void bdrv_qed_init(void) | ||||
|   | ||||
| @@ -848,25 +848,49 @@ static void quorum_close(BlockDriverState *bs) | ||||
|     g_free(s->bs); | ||||
| } | ||||
|  | ||||
| static void quorum_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVQuorumState *s = bs->opaque; | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < s->num_children; i++) { | ||||
|         bdrv_detach_aio_context(s->bs[i]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void quorum_attach_aio_context(BlockDriverState *bs, | ||||
|                                       AioContext *new_context) | ||||
| { | ||||
|     BDRVQuorumState *s = bs->opaque; | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < s->num_children; i++) { | ||||
|         bdrv_attach_aio_context(s->bs[i], new_context); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static BlockDriver bdrv_quorum = { | ||||
|     .format_name        = "quorum", | ||||
|     .protocol_name      = "quorum", | ||||
|     .format_name                        = "quorum", | ||||
|     .protocol_name                      = "quorum", | ||||
|  | ||||
|     .instance_size      = sizeof(BDRVQuorumState), | ||||
|     .instance_size                      = sizeof(BDRVQuorumState), | ||||
|  | ||||
|     .bdrv_file_open     = quorum_open, | ||||
|     .bdrv_close         = quorum_close, | ||||
|     .bdrv_file_open                     = quorum_open, | ||||
|     .bdrv_close                         = quorum_close, | ||||
|  | ||||
|     .bdrv_co_flush_to_disk = quorum_co_flush, | ||||
|     .bdrv_co_flush_to_disk              = quorum_co_flush, | ||||
|  | ||||
|     .bdrv_getlength     = quorum_getlength, | ||||
|     .bdrv_getlength                     = quorum_getlength, | ||||
|  | ||||
|     .bdrv_aio_readv     = quorum_aio_readv, | ||||
|     .bdrv_aio_writev    = quorum_aio_writev, | ||||
|     .bdrv_invalidate_cache = quorum_invalidate_cache, | ||||
|     .bdrv_aio_readv                     = quorum_aio_readv, | ||||
|     .bdrv_aio_writev                    = quorum_aio_writev, | ||||
|     .bdrv_invalidate_cache              = quorum_invalidate_cache, | ||||
|  | ||||
|     .is_filter           = true, | ||||
|     .bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter, | ||||
|     .bdrv_detach_aio_context            = quorum_detach_aio_context, | ||||
|     .bdrv_attach_aio_context            = quorum_attach_aio_context, | ||||
|  | ||||
|     .is_filter                          = true, | ||||
|     .bdrv_recurse_is_first_non_filter   = quorum_recurse_is_first_non_filter, | ||||
| }; | ||||
|  | ||||
| static void bdrv_quorum_init(void) | ||||
|   | ||||
| @@ -34,19 +34,27 @@ | ||||
| /* linux-aio.c - Linux native implementation */ | ||||
| #ifdef CONFIG_LINUX_AIO | ||||
| void *laio_init(void); | ||||
| void laio_cleanup(void *s); | ||||
| BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, | ||||
|         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, | ||||
|         BlockDriverCompletionFunc *cb, void *opaque, int type); | ||||
| void laio_detach_aio_context(void *s, AioContext *old_context); | ||||
| void laio_attach_aio_context(void *s, AioContext *new_context); | ||||
| #endif | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| typedef struct QEMUWin32AIOState QEMUWin32AIOState; | ||||
| QEMUWin32AIOState *win32_aio_init(void); | ||||
| void win32_aio_cleanup(QEMUWin32AIOState *aio); | ||||
| int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile); | ||||
| BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs, | ||||
|         QEMUWin32AIOState *aio, HANDLE hfile, | ||||
|         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, | ||||
|         BlockDriverCompletionFunc *cb, void *opaque, int type); | ||||
| void win32_aio_detach_aio_context(QEMUWin32AIOState *aio, | ||||
|                                   AioContext *old_context); | ||||
| void win32_aio_attach_aio_context(QEMUWin32AIOState *aio, | ||||
|                                   AioContext *new_context); | ||||
| #endif | ||||
|  | ||||
| #endif /* QEMU_RAW_AIO_H */ | ||||
|   | ||||
| @@ -307,6 +307,29 @@ static void raw_parse_flags(int bdrv_flags, int *open_flags) | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void raw_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
| #ifdef CONFIG_LINUX_AIO | ||||
|     BDRVRawState *s = bs->opaque; | ||||
|  | ||||
|     if (s->use_aio) { | ||||
|         laio_detach_aio_context(s->aio_ctx, bdrv_get_aio_context(bs)); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void raw_attach_aio_context(BlockDriverState *bs, | ||||
|                                    AioContext *new_context) | ||||
| { | ||||
| #ifdef CONFIG_LINUX_AIO | ||||
|     BDRVRawState *s = bs->opaque; | ||||
|  | ||||
|     if (s->use_aio) { | ||||
|         laio_attach_aio_context(s->aio_ctx, new_context); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #ifdef CONFIG_LINUX_AIO | ||||
| static int raw_set_aio(void **aio_ctx, int *use_aio, int bdrv_flags) | ||||
| { | ||||
| @@ -447,6 +470,8 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     raw_attach_aio_context(bs, bdrv_get_aio_context(bs)); | ||||
|  | ||||
|     ret = 0; | ||||
| fail: | ||||
|     if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { | ||||
| @@ -1059,6 +1084,14 @@ static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, | ||||
| static void raw_close(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVRawState *s = bs->opaque; | ||||
|  | ||||
|     raw_detach_aio_context(bs); | ||||
|  | ||||
| #ifdef CONFIG_LINUX_AIO | ||||
|     if (s->use_aio) { | ||||
|         laio_cleanup(s->aio_ctx); | ||||
|     } | ||||
| #endif | ||||
|     if (s->fd >= 0) { | ||||
|         qemu_close(s->fd); | ||||
|         s->fd = -1; | ||||
| @@ -1192,7 +1225,7 @@ again: | ||||
|         if (size == 0) | ||||
| #endif | ||||
| #if defined(__APPLE__) && defined(__MACH__) | ||||
|         size = LONG_LONG_MAX; | ||||
|         size = LLONG_MAX; | ||||
| #else | ||||
|         size = lseek(fd, 0LL, SEEK_END); | ||||
| #endif | ||||
| @@ -1478,6 +1511,9 @@ static BlockDriver bdrv_file = { | ||||
|     .bdrv_get_allocated_file_size | ||||
|                         = raw_get_allocated_file_size, | ||||
|  | ||||
|     .bdrv_detach_aio_context = raw_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = raw_attach_aio_context, | ||||
|  | ||||
|     .create_options = raw_create_options, | ||||
| }; | ||||
|  | ||||
| @@ -1878,6 +1914,9 @@ static BlockDriver bdrv_host_device = { | ||||
|     .bdrv_get_allocated_file_size | ||||
|                         = raw_get_allocated_file_size, | ||||
|  | ||||
|     .bdrv_detach_aio_context = raw_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = raw_attach_aio_context, | ||||
|  | ||||
|     /* generic scsi device */ | ||||
| #ifdef __linux__ | ||||
|     .bdrv_ioctl         = hdev_ioctl, | ||||
| @@ -2020,6 +2059,9 @@ static BlockDriver bdrv_host_floppy = { | ||||
|     .bdrv_get_allocated_file_size | ||||
|                         = raw_get_allocated_file_size, | ||||
|  | ||||
|     .bdrv_detach_aio_context = raw_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = raw_attach_aio_context, | ||||
|  | ||||
|     /* removable device support */ | ||||
|     .bdrv_is_inserted   = floppy_is_inserted, | ||||
|     .bdrv_media_changed = floppy_media_changed, | ||||
| @@ -2145,6 +2187,9 @@ static BlockDriver bdrv_host_cdrom = { | ||||
|     .bdrv_get_allocated_file_size | ||||
|                         = raw_get_allocated_file_size, | ||||
|  | ||||
|     .bdrv_detach_aio_context = raw_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = raw_attach_aio_context, | ||||
|  | ||||
|     /* removable device support */ | ||||
|     .bdrv_is_inserted   = cdrom_is_inserted, | ||||
|     .bdrv_eject         = cdrom_eject, | ||||
| @@ -2276,6 +2321,9 @@ static BlockDriver bdrv_host_cdrom = { | ||||
|     .bdrv_get_allocated_file_size | ||||
|                         = raw_get_allocated_file_size, | ||||
|  | ||||
|     .bdrv_detach_aio_context = raw_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = raw_attach_aio_context, | ||||
|  | ||||
|     /* removable device support */ | ||||
|     .bdrv_is_inserted   = cdrom_is_inserted, | ||||
|     .bdrv_eject         = cdrom_eject, | ||||
| @@ -2283,40 +2331,6 @@ static BlockDriver bdrv_host_cdrom = { | ||||
| }; | ||||
| #endif /* __FreeBSD__ */ | ||||
|  | ||||
| #ifdef CONFIG_LINUX_AIO | ||||
| /** | ||||
|  * Return the file descriptor for Linux AIO | ||||
|  * | ||||
|  * This function is a layering violation and should be removed when it becomes | ||||
|  * possible to call the block layer outside the global mutex.  It allows the | ||||
|  * caller to hijack the file descriptor so I/O can be performed outside the | ||||
|  * block layer. | ||||
|  */ | ||||
| int raw_get_aio_fd(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVRawState *s; | ||||
|  | ||||
|     if (!bs->drv) { | ||||
|         return -ENOMEDIUM; | ||||
|     } | ||||
|  | ||||
|     if (bs->drv == bdrv_find_format("raw")) { | ||||
|         bs = bs->file; | ||||
|     } | ||||
|  | ||||
|     /* raw-posix has several protocols so just check for raw_aio_readv */ | ||||
|     if (bs->drv->bdrv_aio_readv != raw_aio_readv) { | ||||
|         return -ENOTSUP; | ||||
|     } | ||||
|  | ||||
|     s = bs->opaque; | ||||
|     if (!s->use_aio) { | ||||
|         return -ENOTSUP; | ||||
|     } | ||||
|     return s->fd; | ||||
| } | ||||
| #endif /* CONFIG_LINUX_AIO */ | ||||
|  | ||||
| static void bdrv_file_init(void) | ||||
| { | ||||
|     /* | ||||
|   | ||||
| @@ -36,8 +36,6 @@ | ||||
| #define FTYPE_CD     1 | ||||
| #define FTYPE_HARDDISK 2 | ||||
|  | ||||
| static QEMUWin32AIOState *aio; | ||||
|  | ||||
| typedef struct RawWin32AIOData { | ||||
|     BlockDriverState *bs; | ||||
|     HANDLE hfile; | ||||
| @@ -202,6 +200,25 @@ static int set_sparse(int fd) | ||||
| 				 NULL, 0, NULL, 0, &returned, NULL); | ||||
| } | ||||
|  | ||||
| static void raw_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVRawState *s = bs->opaque; | ||||
|  | ||||
|     if (s->aio) { | ||||
|         win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void raw_attach_aio_context(BlockDriverState *bs, | ||||
|                                    AioContext *new_context) | ||||
| { | ||||
|     BDRVRawState *s = bs->opaque; | ||||
|  | ||||
|     if (s->aio) { | ||||
|         win32_aio_attach_aio_context(s->aio, new_context); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void raw_probe_alignment(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVRawState *s = bs->opaque; | ||||
| @@ -300,15 +317,6 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|  | ||||
|     raw_parse_flags(flags, &access_flags, &overlapped); | ||||
|  | ||||
|     if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) { | ||||
|         aio = win32_aio_init(); | ||||
|         if (aio == NULL) { | ||||
|             error_setg(errp, "Could not initialize AIO"); | ||||
|             ret = -EINVAL; | ||||
|             goto fail; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (filename[0] && filename[1] == ':') { | ||||
|         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]); | ||||
|     } else if (filename[0] == '\\' && filename[1] == '\\') { | ||||
| @@ -335,13 +343,23 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     } | ||||
|  | ||||
|     if (flags & BDRV_O_NATIVE_AIO) { | ||||
|         ret = win32_aio_attach(aio, s->hfile); | ||||
|         s->aio = win32_aio_init(); | ||||
|         if (s->aio == NULL) { | ||||
|             CloseHandle(s->hfile); | ||||
|             error_setg(errp, "Could not initialize AIO"); | ||||
|             ret = -EINVAL; | ||||
|             goto fail; | ||||
|         } | ||||
|  | ||||
|         ret = win32_aio_attach(s->aio, s->hfile); | ||||
|         if (ret < 0) { | ||||
|             win32_aio_cleanup(s->aio); | ||||
|             CloseHandle(s->hfile); | ||||
|             error_setg_errno(errp, -ret, "Could not enable AIO"); | ||||
|             goto fail; | ||||
|         } | ||||
|         s->aio = aio; | ||||
|  | ||||
|         win32_aio_attach_aio_context(s->aio, bdrv_get_aio_context(bs)); | ||||
|     } | ||||
|  | ||||
|     raw_probe_alignment(bs); | ||||
| @@ -389,6 +407,13 @@ static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, | ||||
| static void raw_close(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVRawState *s = bs->opaque; | ||||
|  | ||||
|     if (s->aio) { | ||||
|         win32_aio_detach_aio_context(s->aio, bdrv_get_aio_context(bs)); | ||||
|         win32_aio_cleanup(s->aio); | ||||
|         s->aio = NULL; | ||||
|     } | ||||
|  | ||||
|     CloseHandle(s->hfile); | ||||
|     if (bs->open_flags & BDRV_O_TEMPORARY) { | ||||
|         unlink(bs->filename); | ||||
| @@ -684,6 +709,9 @@ static BlockDriver bdrv_host_device = { | ||||
|     .bdrv_aio_writev    = raw_aio_writev, | ||||
|     .bdrv_aio_flush     = raw_aio_flush, | ||||
|  | ||||
|     .bdrv_detach_aio_context = raw_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = raw_attach_aio_context, | ||||
|  | ||||
|     .bdrv_getlength      = raw_getlength, | ||||
|     .has_variable_length = true, | ||||
|  | ||||
|   | ||||
							
								
								
									
										81
									
								
								block/rbd.c
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								block/rbd.c
									
									
									
									
									
								
							| @@ -105,7 +105,7 @@ typedef struct BDRVRBDState { | ||||
| static int qemu_rbd_next_tok(char *dst, int dst_len, | ||||
|                              char *src, char delim, | ||||
|                              const char *name, | ||||
|                              char **p) | ||||
|                              char **p, Error **errp) | ||||
| { | ||||
|     int l; | ||||
|     char *end; | ||||
| @@ -128,10 +128,10 @@ static int qemu_rbd_next_tok(char *dst, int dst_len, | ||||
|     } | ||||
|     l = strlen(src); | ||||
|     if (l >= dst_len) { | ||||
|         error_report("%s too long", name); | ||||
|         error_setg(errp, "%s too long", name); | ||||
|         return -EINVAL; | ||||
|     } else if (l == 0) { | ||||
|         error_report("%s too short", name); | ||||
|         error_setg(errp, "%s too short", name); | ||||
|         return -EINVAL; | ||||
|     } | ||||
|  | ||||
| @@ -157,13 +157,15 @@ static int qemu_rbd_parsename(const char *filename, | ||||
|                               char *pool, int pool_len, | ||||
|                               char *snap, int snap_len, | ||||
|                               char *name, int name_len, | ||||
|                               char *conf, int conf_len) | ||||
|                               char *conf, int conf_len, | ||||
|                               Error **errp) | ||||
| { | ||||
|     const char *start; | ||||
|     char *p, *buf; | ||||
|     int ret; | ||||
|  | ||||
|     if (!strstart(filename, "rbd:", &start)) { | ||||
|         error_setg(errp, "File name must start with 'rbd:'"); | ||||
|         return -EINVAL; | ||||
|     } | ||||
|  | ||||
| @@ -172,7 +174,8 @@ static int qemu_rbd_parsename(const char *filename, | ||||
|     *snap = '\0'; | ||||
|     *conf = '\0'; | ||||
|  | ||||
|     ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p); | ||||
|     ret = qemu_rbd_next_tok(pool, pool_len, p, | ||||
|                             '/', "pool name", &p, errp); | ||||
|     if (ret < 0 || !p) { | ||||
|         ret = -EINVAL; | ||||
|         goto done; | ||||
| @@ -180,21 +183,25 @@ static int qemu_rbd_parsename(const char *filename, | ||||
|     qemu_rbd_unescape(pool); | ||||
|  | ||||
|     if (strchr(p, '@')) { | ||||
|         ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p); | ||||
|         ret = qemu_rbd_next_tok(name, name_len, p, | ||||
|                                 '@', "object name", &p, errp); | ||||
|         if (ret < 0) { | ||||
|             goto done; | ||||
|         } | ||||
|         ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p); | ||||
|         ret = qemu_rbd_next_tok(snap, snap_len, p, | ||||
|                                 ':', "snap name", &p, errp); | ||||
|         qemu_rbd_unescape(snap); | ||||
|     } else { | ||||
|         ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p); | ||||
|         ret = qemu_rbd_next_tok(name, name_len, p, | ||||
|                                 ':', "object name", &p, errp); | ||||
|     } | ||||
|     qemu_rbd_unescape(name); | ||||
|     if (ret < 0 || !p) { | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p); | ||||
|     ret = qemu_rbd_next_tok(conf, conf_len, p, | ||||
|                             '\0', "configuration", &p, errp); | ||||
|  | ||||
| done: | ||||
|     g_free(buf); | ||||
| @@ -229,7 +236,7 @@ static char *qemu_rbd_parse_clientname(const char *conf, char *clientname) | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| static int qemu_rbd_set_conf(rados_t cluster, const char *conf) | ||||
| static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp) | ||||
| { | ||||
|     char *p, *buf; | ||||
|     char name[RBD_MAX_CONF_NAME_SIZE]; | ||||
| @@ -241,20 +248,20 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf) | ||||
|  | ||||
|     while (p) { | ||||
|         ret = qemu_rbd_next_tok(name, sizeof(name), p, | ||||
|                                 '=', "conf option name", &p); | ||||
|                                 '=', "conf option name", &p, errp); | ||||
|         if (ret < 0) { | ||||
|             break; | ||||
|         } | ||||
|         qemu_rbd_unescape(name); | ||||
|  | ||||
|         if (!p) { | ||||
|             error_report("conf option %s has no value", name); | ||||
|             error_setg(errp, "conf option %s has no value", name); | ||||
|             ret = -EINVAL; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         ret = qemu_rbd_next_tok(value, sizeof(value), p, | ||||
|                                 ':', "conf option value", &p); | ||||
|                                 ':', "conf option value", &p, errp); | ||||
|         if (ret < 0) { | ||||
|             break; | ||||
|         } | ||||
| @@ -263,7 +270,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf) | ||||
|         if (strcmp(name, "conf") == 0) { | ||||
|             ret = rados_conf_read_file(cluster, value); | ||||
|             if (ret < 0) { | ||||
|                 error_report("error reading conf file %s", value); | ||||
|                 error_setg(errp, "error reading conf file %s", value); | ||||
|                 break; | ||||
|             } | ||||
|         } else if (strcmp(name, "id") == 0) { | ||||
| @@ -271,7 +278,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf) | ||||
|         } else { | ||||
|             ret = rados_conf_set(cluster, name, value); | ||||
|             if (ret < 0) { | ||||
|                 error_report("invalid conf option %s", name); | ||||
|                 error_setg(errp, "invalid conf option %s", name); | ||||
|                 ret = -EINVAL; | ||||
|                 break; | ||||
|             } | ||||
| @@ -285,6 +292,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf) | ||||
| static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options, | ||||
|                            Error **errp) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     int64_t bytes = 0; | ||||
|     int64_t objsize; | ||||
|     int obj_order = 0; | ||||
| @@ -301,7 +309,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options, | ||||
|     if (qemu_rbd_parsename(filename, pool, sizeof(pool), | ||||
|                            snap_buf, sizeof(snap_buf), | ||||
|                            name, sizeof(name), | ||||
|                            conf, sizeof(conf)) < 0) { | ||||
|                            conf, sizeof(conf), &local_err) < 0) { | ||||
|         error_propagate(errp, local_err); | ||||
|         return -EINVAL; | ||||
|     } | ||||
|  | ||||
| @@ -313,11 +322,11 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options, | ||||
|             if (options->value.n) { | ||||
|                 objsize = options->value.n; | ||||
|                 if ((objsize - 1) & objsize) {    /* not a power of 2? */ | ||||
|                     error_report("obj size needs to be power of 2"); | ||||
|                     error_setg(errp, "obj size needs to be power of 2"); | ||||
|                     return -EINVAL; | ||||
|                 } | ||||
|                 if (objsize < 4096) { | ||||
|                     error_report("obj size too small"); | ||||
|                     error_setg(errp, "obj size too small"); | ||||
|                     return -EINVAL; | ||||
|                 } | ||||
|                 obj_order = ffs(objsize) - 1; | ||||
| @@ -328,7 +337,7 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options, | ||||
|  | ||||
|     clientname = qemu_rbd_parse_clientname(conf, clientname_buf); | ||||
|     if (rados_create(&cluster, clientname) < 0) { | ||||
|         error_report("error initializing"); | ||||
|         error_setg(errp, "error initializing"); | ||||
|         return -EIO; | ||||
|     } | ||||
|  | ||||
| @@ -338,20 +347,20 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options, | ||||
|     } | ||||
|  | ||||
|     if (conf[0] != '\0' && | ||||
|         qemu_rbd_set_conf(cluster, conf) < 0) { | ||||
|         error_report("error setting config options"); | ||||
|         qemu_rbd_set_conf(cluster, conf, &local_err) < 0) { | ||||
|         rados_shutdown(cluster); | ||||
|         error_propagate(errp, local_err); | ||||
|         return -EIO; | ||||
|     } | ||||
|  | ||||
|     if (rados_connect(cluster) < 0) { | ||||
|         error_report("error connecting"); | ||||
|         error_setg(errp, "error connecting"); | ||||
|         rados_shutdown(cluster); | ||||
|         return -EIO; | ||||
|     } | ||||
|  | ||||
|     if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) { | ||||
|         error_report("error opening pool %s", pool); | ||||
|         error_setg(errp, "error opening pool %s", pool); | ||||
|         rados_shutdown(cluster); | ||||
|         return -EIO; | ||||
|     } | ||||
| @@ -441,8 +450,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); | ||||
|     qemu_opts_absorb_qdict(opts, options, &local_err); | ||||
|     if (local_err) { | ||||
|         qerror_report_err(local_err); | ||||
|         error_free(local_err); | ||||
|         error_propagate(errp, local_err); | ||||
|         qemu_opts_del(opts); | ||||
|         return -EINVAL; | ||||
|     } | ||||
| @@ -452,7 +460,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     if (qemu_rbd_parsename(filename, pool, sizeof(pool), | ||||
|                            snap_buf, sizeof(snap_buf), | ||||
|                            s->name, sizeof(s->name), | ||||
|                            conf, sizeof(conf)) < 0) { | ||||
|                            conf, sizeof(conf), errp) < 0) { | ||||
|         r = -EINVAL; | ||||
|         goto failed_opts; | ||||
|     } | ||||
| @@ -460,7 +468,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     clientname = qemu_rbd_parse_clientname(conf, clientname_buf); | ||||
|     r = rados_create(&s->cluster, clientname); | ||||
|     if (r < 0) { | ||||
|         error_report("error initializing"); | ||||
|         error_setg(&local_err, "error initializing"); | ||||
|         goto failed_opts; | ||||
|     } | ||||
|  | ||||
| @@ -488,28 +496,27 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     } | ||||
|  | ||||
|     if (conf[0] != '\0') { | ||||
|         r = qemu_rbd_set_conf(s->cluster, conf); | ||||
|         r = qemu_rbd_set_conf(s->cluster, conf, errp); | ||||
|         if (r < 0) { | ||||
|             error_report("error setting config options"); | ||||
|             goto failed_shutdown; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     r = rados_connect(s->cluster); | ||||
|     if (r < 0) { | ||||
|         error_report("error connecting"); | ||||
|         error_setg(&local_err, "error connecting"); | ||||
|         goto failed_shutdown; | ||||
|     } | ||||
|  | ||||
|     r = rados_ioctx_create(s->cluster, pool, &s->io_ctx); | ||||
|     if (r < 0) { | ||||
|         error_report("error opening pool %s", pool); | ||||
|         error_setg(&local_err, "error opening pool %s", pool); | ||||
|         goto failed_shutdown; | ||||
|     } | ||||
|  | ||||
|     r = rbd_open(s->io_ctx, s->name, &s->image, s->snap); | ||||
|     if (r < 0) { | ||||
|         error_report("error reading header from %s", s->name); | ||||
|         error_setg(&local_err, "error reading header from %s", s->name); | ||||
|         goto failed_open; | ||||
|     } | ||||
|  | ||||
| @@ -548,7 +555,7 @@ static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb) | ||||
|     acb->cancelled = 1; | ||||
|  | ||||
|     while (acb->status == -EINPROGRESS) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(bdrv_get_aio_context(acb->common.bs), true); | ||||
|     } | ||||
|  | ||||
|     qemu_aio_release(acb); | ||||
| @@ -581,7 +588,8 @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb) | ||||
|     rcb->ret = rbd_aio_get_return_value(c); | ||||
|     rbd_aio_release(c); | ||||
|  | ||||
|     acb->bh = qemu_bh_new(rbd_finish_bh, rcb); | ||||
|     acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs), | ||||
|                          rbd_finish_bh, rcb); | ||||
|     qemu_bh_schedule(acb->bh); | ||||
| } | ||||
|  | ||||
| @@ -677,13 +685,16 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs, | ||||
|     } | ||||
|  | ||||
|     if (r < 0) { | ||||
|         goto failed; | ||||
|         goto failed_completion; | ||||
|     } | ||||
|  | ||||
|     return &acb->common; | ||||
|  | ||||
| failed_completion: | ||||
|     rbd_aio_release(c); | ||||
| failed: | ||||
|     g_free(rcb); | ||||
|     qemu_vfree(acb->bounce); | ||||
|     qemu_aio_release(acb); | ||||
|     return NULL; | ||||
| } | ||||
|   | ||||
							
								
								
									
										320
									
								
								block/sheepdog.c
									
									
									
									
									
								
							
							
						
						
									
										320
									
								
								block/sheepdog.c
									
									
									
									
									
								
							| @@ -200,6 +200,8 @@ typedef struct SheepdogInode { | ||||
|     uint32_t data_vdi_id[MAX_DATA_OBJS]; | ||||
| } SheepdogInode; | ||||
|  | ||||
| #define SD_INODE_HEADER_SIZE offsetof(SheepdogInode, data_vdi_id) | ||||
|  | ||||
| /* | ||||
|  * 64 bit FNV-1a non-zero initial basis | ||||
|  */ | ||||
| @@ -282,6 +284,7 @@ typedef struct AIOReq { | ||||
|     unsigned int data_len; | ||||
|     uint8_t flags; | ||||
|     uint32_t id; | ||||
|     bool create; | ||||
|  | ||||
|     QLIST_ENTRY(AIOReq) aio_siblings; | ||||
| } AIOReq; | ||||
| @@ -314,6 +317,7 @@ struct SheepdogAIOCB { | ||||
|  | ||||
| typedef struct BDRVSheepdogState { | ||||
|     BlockDriverState *bs; | ||||
|     AioContext *aio_context; | ||||
|  | ||||
|     SheepdogInode inode; | ||||
|  | ||||
| @@ -404,7 +408,7 @@ static const char * sd_strerror(int err) | ||||
|  | ||||
| static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb, | ||||
|                                     uint64_t oid, unsigned int data_len, | ||||
|                                     uint64_t offset, uint8_t flags, | ||||
|                                     uint64_t offset, uint8_t flags, bool create, | ||||
|                                     uint64_t base_oid, unsigned int iov_offset) | ||||
| { | ||||
|     AIOReq *aio_req; | ||||
| @@ -418,6 +422,7 @@ static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb, | ||||
|     aio_req->data_len = data_len; | ||||
|     aio_req->flags = flags; | ||||
|     aio_req->id = s->aioreq_seq_num++; | ||||
|     aio_req->create = create; | ||||
|  | ||||
|     acb->nr_pending++; | ||||
|     return aio_req; | ||||
| @@ -496,7 +501,7 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb) | ||||
|             sd_finish_aiocb(acb); | ||||
|             return; | ||||
|         } | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(s->aio_context, true); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -526,17 +531,16 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, | ||||
|     return acb; | ||||
| } | ||||
|  | ||||
| static int connect_to_sdog(BDRVSheepdogState *s) | ||||
| static int connect_to_sdog(BDRVSheepdogState *s, Error **errp) | ||||
| { | ||||
|     int fd; | ||||
|     Error *err = NULL; | ||||
|  | ||||
|     if (s->is_unix) { | ||||
|         fd = unix_connect(s->host_spec, &err); | ||||
|         fd = unix_connect(s->host_spec, errp); | ||||
|     } else { | ||||
|         fd = inet_connect(s->host_spec, &err); | ||||
|         fd = inet_connect(s->host_spec, errp); | ||||
|  | ||||
|         if (err == NULL) { | ||||
|         if (fd >= 0) { | ||||
|             int ret = socket_set_nodelay(fd); | ||||
|             if (ret < 0) { | ||||
|                 error_report("%s", strerror(errno)); | ||||
| @@ -544,10 +548,7 @@ static int connect_to_sdog(BDRVSheepdogState *s) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (err != NULL) { | ||||
|         qerror_report_err(err); | ||||
|         error_free(err); | ||||
|     } else { | ||||
|     if (fd >= 0) { | ||||
|         qemu_set_nonblock(fd); | ||||
|     } | ||||
|  | ||||
| @@ -582,6 +583,7 @@ static void restart_co_req(void *opaque) | ||||
|  | ||||
| typedef struct SheepdogReqCo { | ||||
|     int sockfd; | ||||
|     AioContext *aio_context; | ||||
|     SheepdogReq *hdr; | ||||
|     void *data; | ||||
|     unsigned int *wlen; | ||||
| @@ -602,14 +604,14 @@ static coroutine_fn void do_co_req(void *opaque) | ||||
|     unsigned int *rlen = srco->rlen; | ||||
|  | ||||
|     co = qemu_coroutine_self(); | ||||
|     qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, co); | ||||
|     aio_set_fd_handler(srco->aio_context, sockfd, NULL, restart_co_req, co); | ||||
|  | ||||
|     ret = send_co_req(sockfd, hdr, data, wlen); | ||||
|     if (ret < 0) { | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, co); | ||||
|     aio_set_fd_handler(srco->aio_context, sockfd, restart_co_req, NULL, co); | ||||
|  | ||||
|     ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr)); | ||||
|     if (ret != sizeof(*hdr)) { | ||||
| @@ -634,18 +636,19 @@ static coroutine_fn void do_co_req(void *opaque) | ||||
| out: | ||||
|     /* there is at most one request for this sockfd, so it is safe to | ||||
|      * set each handler to NULL. */ | ||||
|     qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL); | ||||
|     aio_set_fd_handler(srco->aio_context, sockfd, NULL, NULL, NULL); | ||||
|  | ||||
|     srco->ret = ret; | ||||
|     srco->finished = true; | ||||
| } | ||||
|  | ||||
| static int do_req(int sockfd, SheepdogReq *hdr, void *data, | ||||
|                   unsigned int *wlen, unsigned int *rlen) | ||||
| static int do_req(int sockfd, AioContext *aio_context, SheepdogReq *hdr, | ||||
|                   void *data, unsigned int *wlen, unsigned int *rlen) | ||||
| { | ||||
|     Coroutine *co; | ||||
|     SheepdogReqCo srco = { | ||||
|         .sockfd = sockfd, | ||||
|         .aio_context = aio_context, | ||||
|         .hdr = hdr, | ||||
|         .data = data, | ||||
|         .wlen = wlen, | ||||
| @@ -660,7 +663,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, | ||||
|         co = qemu_coroutine_create(do_co_req); | ||||
|         qemu_coroutine_enter(co, &srco); | ||||
|         while (!srco.finished) { | ||||
|             qemu_aio_wait(); | ||||
|             aio_poll(aio_context, true); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -668,11 +671,11 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, | ||||
| } | ||||
|  | ||||
| static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, | ||||
|                            struct iovec *iov, int niov, bool create, | ||||
|                            enum AIOCBState aiocb_type); | ||||
|                                          struct iovec *iov, int niov, | ||||
|                                          enum AIOCBState aiocb_type); | ||||
| static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req); | ||||
| static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag); | ||||
| static int get_sheep_fd(BDRVSheepdogState *s); | ||||
| static int get_sheep_fd(BDRVSheepdogState *s, Error **errp); | ||||
| static void co_write_request(void *opaque); | ||||
|  | ||||
| static AIOReq *find_pending_req(BDRVSheepdogState *s, uint64_t oid) | ||||
| @@ -702,17 +705,18 @@ static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid) | ||||
|         /* move aio_req from pending list to inflight one */ | ||||
|         QLIST_REMOVE(aio_req, aio_siblings); | ||||
|         QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); | ||||
|         add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, false, | ||||
|         add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, | ||||
|                         acb->aiocb_type); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static coroutine_fn void reconnect_to_sdog(void *opaque) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     BDRVSheepdogState *s = opaque; | ||||
|     AIOReq *aio_req, *next; | ||||
|  | ||||
|     qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL); | ||||
|     aio_set_fd_handler(s->aio_context, s->fd, NULL, NULL, NULL); | ||||
|     close(s->fd); | ||||
|     s->fd = -1; | ||||
|  | ||||
| @@ -723,9 +727,11 @@ static coroutine_fn void reconnect_to_sdog(void *opaque) | ||||
|  | ||||
|     /* Try to reconnect the sheepdog server every one second. */ | ||||
|     while (s->fd < 0) { | ||||
|         s->fd = get_sheep_fd(s); | ||||
|         s->fd = get_sheep_fd(s, &local_err); | ||||
|         if (s->fd < 0) { | ||||
|             DPRINTF("Wait for connection to be established\n"); | ||||
|             error_report("%s", error_get_pretty(local_err)); | ||||
|             error_free(local_err); | ||||
|             co_aio_sleep_ns(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME, | ||||
|                             1000000000ULL); | ||||
|         } | ||||
| @@ -798,7 +804,7 @@ static void coroutine_fn aio_read_response(void *opaque) | ||||
|         } | ||||
|         idx = data_oid_to_idx(aio_req->oid); | ||||
|  | ||||
|         if (s->inode.data_vdi_id[idx] != s->inode.vdi_id) { | ||||
|         if (aio_req->create) { | ||||
|             /* | ||||
|              * If the object is newly created one, we need to update | ||||
|              * the vdi object (metadata object).  min_dirty_data_idx | ||||
| @@ -914,16 +920,16 @@ static void co_write_request(void *opaque) | ||||
|  * We cannot use this descriptor for other operations because | ||||
|  * the block driver may be on waiting response from the server. | ||||
|  */ | ||||
| static int get_sheep_fd(BDRVSheepdogState *s) | ||||
| static int get_sheep_fd(BDRVSheepdogState *s, Error **errp) | ||||
| { | ||||
|     int fd; | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, errp); | ||||
|     if (fd < 0) { | ||||
|         return fd; | ||||
|     } | ||||
|  | ||||
|     qemu_aio_set_fd_handler(fd, co_read_response, NULL, s); | ||||
|     aio_set_fd_handler(s->aio_context, fd, co_read_response, NULL, s); | ||||
|     return fd; | ||||
| } | ||||
|  | ||||
| @@ -1061,7 +1067,7 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename, | ||||
|  | ||||
| static int find_vdi_name(BDRVSheepdogState *s, const char *filename, | ||||
|                          uint32_t snapid, const char *tag, uint32_t *vid, | ||||
|                          bool lock) | ||||
|                          bool lock, Error **errp) | ||||
| { | ||||
|     int ret, fd; | ||||
|     SheepdogVdiReq hdr; | ||||
| @@ -1069,7 +1075,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename, | ||||
|     unsigned int wlen, rlen = 0; | ||||
|     char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN]; | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, errp); | ||||
|     if (fd < 0) { | ||||
|         return fd; | ||||
|     } | ||||
| @@ -1093,14 +1099,15 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename, | ||||
|     hdr.snapid = snapid; | ||||
|     hdr.flags = SD_FLAG_CMD_WRITE; | ||||
|  | ||||
|     ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen); | ||||
|     ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen); | ||||
|     if (ret) { | ||||
|         error_setg_errno(errp, -ret, "cannot get vdi info"); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     if (rsp->result != SD_RES_SUCCESS) { | ||||
|         error_report("cannot get vdi info, %s, %s %" PRIu32 " %s", | ||||
|                      sd_strerror(rsp->result), filename, snapid, tag); | ||||
|         error_setg(errp, "cannot get vdi info, %s, %s %" PRIu32 " %s", | ||||
|                    sd_strerror(rsp->result), filename, snapid, tag); | ||||
|         if (rsp->result == SD_RES_NO_VDI) { | ||||
|             ret = -ENOENT; | ||||
|         } else { | ||||
| @@ -1117,8 +1124,8 @@ out: | ||||
| } | ||||
|  | ||||
| static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, | ||||
|                            struct iovec *iov, int niov, bool create, | ||||
|                            enum AIOCBState aiocb_type) | ||||
|                                          struct iovec *iov, int niov, | ||||
|                                          enum AIOCBState aiocb_type) | ||||
| { | ||||
|     int nr_copies = s->inode.nr_copies; | ||||
|     SheepdogObjReq hdr; | ||||
| @@ -1129,6 +1136,7 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, | ||||
|     uint64_t offset = aio_req->offset; | ||||
|     uint8_t flags = aio_req->flags; | ||||
|     uint64_t old_oid = aio_req->base_oid; | ||||
|     bool create = aio_req->create; | ||||
|  | ||||
|     if (!nr_copies) { | ||||
|         error_report("bug"); | ||||
| @@ -1173,7 +1181,8 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, | ||||
|  | ||||
|     qemu_co_mutex_lock(&s->lock); | ||||
|     s->co_send = qemu_coroutine_self(); | ||||
|     qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request, s); | ||||
|     aio_set_fd_handler(s->aio_context, s->fd, | ||||
|                        co_read_response, co_write_request, s); | ||||
|     socket_set_cork(s->fd, 1); | ||||
|  | ||||
|     /* send a header */ | ||||
| @@ -1191,12 +1200,13 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, | ||||
|     } | ||||
| out: | ||||
|     socket_set_cork(s->fd, 0); | ||||
|     qemu_aio_set_fd_handler(s->fd, co_read_response, NULL, s); | ||||
|     aio_set_fd_handler(s->aio_context, s->fd, co_read_response, NULL, s); | ||||
|     s->co_send = NULL; | ||||
|     qemu_co_mutex_unlock(&s->lock); | ||||
| } | ||||
|  | ||||
| static int read_write_object(int fd, char *buf, uint64_t oid, uint8_t copies, | ||||
| static int read_write_object(int fd, AioContext *aio_context, char *buf, | ||||
|                              uint64_t oid, uint8_t copies, | ||||
|                              unsigned int datalen, uint64_t offset, | ||||
|                              bool write, bool create, uint32_t cache_flags) | ||||
| { | ||||
| @@ -1229,7 +1239,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, uint8_t copies, | ||||
|     hdr.offset = offset; | ||||
|     hdr.copies = copies; | ||||
|  | ||||
|     ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen); | ||||
|     ret = do_req(fd, aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen); | ||||
|     if (ret) { | ||||
|         error_report("failed to send a request to the sheep"); | ||||
|         return ret; | ||||
| @@ -1244,49 +1254,59 @@ static int read_write_object(int fd, char *buf, uint64_t oid, uint8_t copies, | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int read_object(int fd, char *buf, uint64_t oid, uint8_t copies, | ||||
| static int read_object(int fd, AioContext *aio_context, char *buf, | ||||
|                        uint64_t oid, uint8_t copies, | ||||
|                        unsigned int datalen, uint64_t offset, | ||||
|                        uint32_t cache_flags) | ||||
| { | ||||
|     return read_write_object(fd, buf, oid, copies, datalen, offset, false, | ||||
|     return read_write_object(fd, aio_context, buf, oid, copies, | ||||
|                              datalen, offset, false, | ||||
|                              false, cache_flags); | ||||
| } | ||||
|  | ||||
| static int write_object(int fd, char *buf, uint64_t oid, uint8_t copies, | ||||
| static int write_object(int fd, AioContext *aio_context, char *buf, | ||||
|                         uint64_t oid, uint8_t copies, | ||||
|                         unsigned int datalen, uint64_t offset, bool create, | ||||
|                         uint32_t cache_flags) | ||||
| { | ||||
|     return read_write_object(fd, buf, oid, copies, datalen, offset, true, | ||||
|     return read_write_object(fd, aio_context, buf, oid, copies, | ||||
|                              datalen, offset, true, | ||||
|                              create, cache_flags); | ||||
| } | ||||
|  | ||||
| /* update inode with the latest state */ | ||||
| static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     SheepdogInode *inode; | ||||
|     int ret = 0, fd; | ||||
|     uint32_t vid = 0; | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         return -EIO; | ||||
|     } | ||||
|  | ||||
|     inode = g_malloc(sizeof(s->inode)); | ||||
|     inode = g_malloc(SD_INODE_HEADER_SIZE); | ||||
|  | ||||
|     ret = find_vdi_name(s, s->name, snapid, tag, &vid, false); | ||||
|     ret = find_vdi_name(s, s->name, snapid, tag, &vid, false, &local_err); | ||||
|     if (ret) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     ret = read_object(fd, (char *)inode, vid_to_vdi_oid(vid), | ||||
|                       s->inode.nr_copies, sizeof(*inode), 0, s->cache_flags); | ||||
|     ret = read_object(fd, s->aio_context, (char *)inode, vid_to_vdi_oid(vid), | ||||
|                       s->inode.nr_copies, SD_INODE_HEADER_SIZE, 0, | ||||
|                       s->cache_flags); | ||||
|     if (ret < 0) { | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     if (inode->vdi_id != s->inode.vdi_id) { | ||||
|         memcpy(&s->inode, inode, sizeof(s->inode)); | ||||
|         memcpy(&s->inode, inode, SD_INODE_HEADER_SIZE); | ||||
|     } | ||||
|  | ||||
| out: | ||||
| @@ -1310,6 +1330,7 @@ static bool check_simultaneous_create(BDRVSheepdogState *s, AIOReq *aio_req) | ||||
|             DPRINTF("simultaneous create to %" PRIx64 "\n", aio_req->oid); | ||||
|             aio_req->flags = 0; | ||||
|             aio_req->base_oid = 0; | ||||
|             aio_req->create = false; | ||||
|             QLIST_REMOVE(aio_req, aio_siblings); | ||||
|             QLIST_INSERT_HEAD(&s->pending_aio_head, aio_req, aio_siblings); | ||||
|             return true; | ||||
| @@ -1322,7 +1343,8 @@ static bool check_simultaneous_create(BDRVSheepdogState *s, AIOReq *aio_req) | ||||
| static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req) | ||||
| { | ||||
|     SheepdogAIOCB *acb = aio_req->aiocb; | ||||
|     bool create = false; | ||||
|  | ||||
|     aio_req->create = false; | ||||
|  | ||||
|     /* check whether this request becomes a CoW one */ | ||||
|     if (acb->aiocb_type == AIOCB_WRITE_UDATA && is_data_obj(aio_req->oid)) { | ||||
| @@ -1340,20 +1362,36 @@ static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req) | ||||
|             aio_req->base_oid = vid_to_data_oid(s->inode.data_vdi_id[idx], idx); | ||||
|             aio_req->flags |= SD_FLAG_CMD_COW; | ||||
|         } | ||||
|         create = true; | ||||
|         aio_req->create = true; | ||||
|     } | ||||
| out: | ||||
|     if (is_data_obj(aio_req->oid)) { | ||||
|         add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, create, | ||||
|         add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, | ||||
|                         acb->aiocb_type); | ||||
|     } else { | ||||
|         struct iovec iov; | ||||
|         iov.iov_base = &s->inode; | ||||
|         iov.iov_len = sizeof(s->inode); | ||||
|         add_aio_request(s, aio_req, &iov, 1, false, AIOCB_WRITE_UDATA); | ||||
|         add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void sd_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVSheepdogState *s = bs->opaque; | ||||
|  | ||||
|     aio_set_fd_handler(s->aio_context, s->fd, NULL, NULL, NULL); | ||||
| } | ||||
|  | ||||
| static void sd_attach_aio_context(BlockDriverState *bs, | ||||
|                                   AioContext *new_context) | ||||
| { | ||||
|     BDRVSheepdogState *s = bs->opaque; | ||||
|  | ||||
|     s->aio_context = new_context; | ||||
|     aio_set_fd_handler(new_context, s->fd, co_read_response, NULL, s); | ||||
| } | ||||
|  | ||||
| /* TODO Convert to fine grained options */ | ||||
| static QemuOptsList runtime_opts = { | ||||
|     .name = "sheepdog", | ||||
| @@ -1382,12 +1420,12 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     const char *filename; | ||||
|  | ||||
|     s->bs = bs; | ||||
|     s->aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
|     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); | ||||
|     qemu_opts_absorb_qdict(opts, options, &local_err); | ||||
|     if (local_err) { | ||||
|         qerror_report_err(local_err); | ||||
|         error_free(local_err); | ||||
|         error_propagate(errp, local_err); | ||||
|         ret = -EINVAL; | ||||
|         goto out; | ||||
|     } | ||||
| @@ -1408,15 +1446,16 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|         ret = parse_vdiname(s, filename, vdi, &snapid, tag); | ||||
|     } | ||||
|     if (ret < 0) { | ||||
|         error_setg(errp, "Can't parse filename"); | ||||
|         goto out; | ||||
|     } | ||||
|     s->fd = get_sheep_fd(s); | ||||
|     s->fd = get_sheep_fd(s, errp); | ||||
|     if (s->fd < 0) { | ||||
|         ret = s->fd; | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     ret = find_vdi_name(s, vdi, snapid, tag, &vid, true); | ||||
|     ret = find_vdi_name(s, vdi, snapid, tag, &vid, true, errp); | ||||
|     if (ret) { | ||||
|         goto out; | ||||
|     } | ||||
| @@ -1436,19 +1475,20 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|         s->is_snapshot = true; | ||||
|     } | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, errp); | ||||
|     if (fd < 0) { | ||||
|         ret = fd; | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     buf = g_malloc(SD_INODE_SIZE); | ||||
|     ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0, | ||||
|                       s->cache_flags); | ||||
|     ret = read_object(fd, s->aio_context, buf, vid_to_vdi_oid(vid), | ||||
|                       0, SD_INODE_SIZE, 0, s->cache_flags); | ||||
|  | ||||
|     closesocket(fd); | ||||
|  | ||||
|     if (ret) { | ||||
|         error_setg(errp, "Can't read snapshot inode"); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
| @@ -1463,7 +1503,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, | ||||
|     g_free(buf); | ||||
|     return 0; | ||||
| out: | ||||
|     qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL); | ||||
|     aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, NULL, NULL, NULL); | ||||
|     if (s->fd >= 0) { | ||||
|         closesocket(s->fd); | ||||
|     } | ||||
| @@ -1472,7 +1512,8 @@ out: | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot) | ||||
| static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot, | ||||
|                         Error **errp) | ||||
| { | ||||
|     SheepdogVdiReq hdr; | ||||
|     SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; | ||||
| @@ -1480,7 +1521,7 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot) | ||||
|     unsigned int wlen, rlen = 0; | ||||
|     char buf[SD_MAX_VDI_LEN]; | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, errp); | ||||
|     if (fd < 0) { | ||||
|         return fd; | ||||
|     } | ||||
| @@ -1505,16 +1546,17 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot) | ||||
|     hdr.copy_policy = s->inode.copy_policy; | ||||
|     hdr.copies = s->inode.nr_copies; | ||||
|  | ||||
|     ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen); | ||||
|     ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen); | ||||
|  | ||||
|     closesocket(fd); | ||||
|  | ||||
|     if (ret) { | ||||
|         error_setg_errno(errp, -ret, "create failed"); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     if (rsp->result != SD_RES_SUCCESS) { | ||||
|         error_report("%s, %s", sd_strerror(rsp->result), s->inode.name); | ||||
|         error_setg(errp, "%s, %s", sd_strerror(rsp->result), s->inode.name); | ||||
|         return -EIO; | ||||
|     } | ||||
|  | ||||
| @@ -1525,21 +1567,18 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot) | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int sd_prealloc(const char *filename) | ||||
| static int sd_prealloc(const char *filename, Error **errp) | ||||
| { | ||||
|     BlockDriverState *bs = NULL; | ||||
|     uint32_t idx, max_idx; | ||||
|     int64_t vdi_size; | ||||
|     void *buf = g_malloc0(SD_DATA_OBJ_SIZE); | ||||
|     Error *local_err = NULL; | ||||
|     int ret; | ||||
|  | ||||
|     ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, | ||||
|                     NULL, &local_err); | ||||
|                     NULL, errp); | ||||
|     if (ret < 0) { | ||||
|         qerror_report_err(local_err); | ||||
|         error_free(local_err); | ||||
|         goto out; | ||||
|         goto out_with_err_set; | ||||
|     } | ||||
|  | ||||
|     vdi_size = bdrv_getlength(bs); | ||||
| @@ -1563,7 +1602,12 @@ static int sd_prealloc(const char *filename) | ||||
|             goto out; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| out: | ||||
|     if (ret < 0) { | ||||
|         error_setg_errno(errp, -ret, "Can't pre-allocate"); | ||||
|     } | ||||
| out_with_err_set: | ||||
|     if (bs) { | ||||
|         bdrv_unref(bs); | ||||
|     } | ||||
| @@ -1636,7 +1680,6 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, | ||||
|     char tag[SD_MAX_VDI_TAG_LEN]; | ||||
|     uint32_t snapid; | ||||
|     bool prealloc = false; | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     s = g_malloc0(sizeof(BDRVSheepdogState)); | ||||
|  | ||||
| @@ -1647,6 +1690,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, | ||||
|         ret = parse_vdiname(s, filename, s->name, &snapid, tag); | ||||
|     } | ||||
|     if (ret < 0) { | ||||
|         error_setg(errp, "Can't parse filename"); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
| @@ -1661,8 +1705,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, | ||||
|             } else if (!strcmp(options->value.s, "full")) { | ||||
|                 prealloc = true; | ||||
|             } else { | ||||
|                 error_report("Invalid preallocation mode: '%s'", | ||||
|                              options->value.s); | ||||
|                 error_setg(errp, "Invalid preallocation mode: '%s'", | ||||
|                            options->value.s); | ||||
|                 ret = -EINVAL; | ||||
|                 goto out; | ||||
|             } | ||||
| @@ -1670,6 +1714,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, | ||||
|             if (options->value.s) { | ||||
|                 ret = parse_redundancy(s, options->value.s); | ||||
|                 if (ret < 0) { | ||||
|                     error_setg(errp, "Invalid redundancy mode: '%s'", | ||||
|                                options->value.s); | ||||
|                     goto out; | ||||
|                 } | ||||
|             } | ||||
| @@ -1678,7 +1724,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, | ||||
|     } | ||||
|  | ||||
|     if (s->inode.vdi_size > SD_MAX_VDI_SIZE) { | ||||
|         error_report("too big image size"); | ||||
|         error_setg(errp, "too big image size"); | ||||
|         ret = -EINVAL; | ||||
|         goto out; | ||||
|     } | ||||
| @@ -1691,24 +1737,22 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, | ||||
|         /* Currently, only Sheepdog backing image is supported. */ | ||||
|         drv = bdrv_find_protocol(backing_file, true); | ||||
|         if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) { | ||||
|             error_report("backing_file must be a sheepdog image"); | ||||
|             error_setg(errp, "backing_file must be a sheepdog image"); | ||||
|             ret = -EINVAL; | ||||
|             goto out; | ||||
|         } | ||||
|  | ||||
|         bs = NULL; | ||||
|         ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_PROTOCOL, NULL, | ||||
|                         &local_err); | ||||
|                         errp); | ||||
|         if (ret < 0) { | ||||
|             qerror_report_err(local_err); | ||||
|             error_free(local_err); | ||||
|             goto out; | ||||
|         } | ||||
|  | ||||
|         base = bs->opaque; | ||||
|  | ||||
|         if (!is_snapshot(&base->inode)) { | ||||
|             error_report("cannot clone from a non snapshot vdi"); | ||||
|             error_setg(errp, "cannot clone from a non snapshot vdi"); | ||||
|             bdrv_unref(bs); | ||||
|             ret = -EINVAL; | ||||
|             goto out; | ||||
| @@ -1717,12 +1761,14 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, | ||||
|         bdrv_unref(bs); | ||||
|     } | ||||
|  | ||||
|     ret = do_sd_create(s, &vid, 0); | ||||
|     if (!prealloc || ret) { | ||||
|     ret = do_sd_create(s, &vid, 0, errp); | ||||
|     if (ret) { | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     ret = sd_prealloc(filename); | ||||
|     if (prealloc) { | ||||
|         ret = sd_prealloc(filename, errp); | ||||
|     } | ||||
| out: | ||||
|     g_free(s); | ||||
|     return ret; | ||||
| @@ -1730,6 +1776,7 @@ out: | ||||
|  | ||||
| static void sd_close(BlockDriverState *bs) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     BDRVSheepdogState *s = bs->opaque; | ||||
|     SheepdogVdiReq hdr; | ||||
|     SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; | ||||
| @@ -1738,8 +1785,10 @@ static void sd_close(BlockDriverState *bs) | ||||
|  | ||||
|     DPRINTF("%s\n", s->name); | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -1751,7 +1800,8 @@ static void sd_close(BlockDriverState *bs) | ||||
|     hdr.data_length = wlen; | ||||
|     hdr.flags = SD_FLAG_CMD_WRITE; | ||||
|  | ||||
|     ret = do_req(fd, (SheepdogReq *)&hdr, s->name, &wlen, &rlen); | ||||
|     ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, | ||||
|                  s->name, &wlen, &rlen); | ||||
|  | ||||
|     closesocket(fd); | ||||
|  | ||||
| @@ -1760,7 +1810,7 @@ static void sd_close(BlockDriverState *bs) | ||||
|         error_report("%s, %s", sd_strerror(rsp->result), s->name); | ||||
|     } | ||||
|  | ||||
|     qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL); | ||||
|     aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, NULL, NULL, NULL); | ||||
|     closesocket(s->fd); | ||||
|     g_free(s->host_spec); | ||||
| } | ||||
| @@ -1774,6 +1824,7 @@ static int64_t sd_getlength(BlockDriverState *bs) | ||||
|  | ||||
| static int sd_truncate(BlockDriverState *bs, int64_t offset) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     BDRVSheepdogState *s = bs->opaque; | ||||
|     int ret, fd; | ||||
|     unsigned int datalen; | ||||
| @@ -1786,16 +1837,19 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) | ||||
|         return -EINVAL; | ||||
|     } | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         return fd; | ||||
|     } | ||||
|  | ||||
|     /* we don't need to update entire object */ | ||||
|     datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id); | ||||
|     s->inode.vdi_size = offset; | ||||
|     ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id), | ||||
|                        s->inode.nr_copies, datalen, 0, false, s->cache_flags); | ||||
|     ret = write_object(fd, s->aio_context, (char *)&s->inode, | ||||
|                        vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies, | ||||
|                        datalen, 0, false, s->cache_flags); | ||||
|     close(fd); | ||||
|  | ||||
|     if (ret < 0) { | ||||
| @@ -1831,9 +1885,9 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) | ||||
|         iov.iov_base = &s->inode; | ||||
|         iov.iov_len = sizeof(s->inode); | ||||
|         aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), | ||||
|                                 data_len, offset, 0, 0, offset); | ||||
|                                 data_len, offset, 0, false, 0, offset); | ||||
|         QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); | ||||
|         add_aio_request(s, aio_req, &iov, 1, false, AIOCB_WRITE_UDATA); | ||||
|         add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA); | ||||
|  | ||||
|         acb->aio_done_func = sd_finish_aiocb; | ||||
|         acb->aiocb_type = AIOCB_WRITE_UDATA; | ||||
| @@ -1846,6 +1900,7 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) | ||||
| /* Delete current working VDI on the snapshot chain */ | ||||
| static bool sd_delete(BDRVSheepdogState *s) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     unsigned int wlen = SD_MAX_VDI_LEN, rlen = 0; | ||||
|     SheepdogVdiReq hdr = { | ||||
|         .opcode = SD_OP_DEL_VDI, | ||||
| @@ -1856,12 +1911,15 @@ static bool sd_delete(BDRVSheepdogState *s) | ||||
|     SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; | ||||
|     int fd, ret; | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     ret = do_req(fd, (SheepdogReq *)&hdr, s->name, &wlen, &rlen); | ||||
|     ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, | ||||
|                  s->name, &wlen, &rlen); | ||||
|     closesocket(fd); | ||||
|     if (ret) { | ||||
|         return false; | ||||
| @@ -1885,6 +1943,7 @@ static bool sd_delete(BDRVSheepdogState *s) | ||||
|  */ | ||||
| static int sd_create_branch(BDRVSheepdogState *s) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     int ret, fd; | ||||
|     uint32_t vid; | ||||
|     char *buf; | ||||
| @@ -1900,21 +1959,25 @@ static int sd_create_branch(BDRVSheepdogState *s) | ||||
|      * false bail out. | ||||
|      */ | ||||
|     deleted = sd_delete(s); | ||||
|     ret = do_sd_create(s, &vid, !deleted); | ||||
|     ret = do_sd_create(s, &vid, !deleted, &local_err); | ||||
|     if (ret) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     DPRINTF("%" PRIx32 " is created.\n", vid); | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         ret = fd; | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies, | ||||
|                       SD_INODE_SIZE, 0, s->cache_flags); | ||||
|     ret = read_object(fd, s->aio_context, buf, vid_to_vdi_oid(vid), | ||||
|                       s->inode.nr_copies, SD_INODE_SIZE, 0, s->cache_flags); | ||||
|  | ||||
|     closesocket(fd); | ||||
|  | ||||
| @@ -2023,7 +2086,8 @@ static int coroutine_fn sd_co_rw_vector(void *p) | ||||
|             DPRINTF("new oid %" PRIx64 "\n", oid); | ||||
|         } | ||||
|  | ||||
|         aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, old_oid, done); | ||||
|         aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, create, | ||||
|                                 old_oid, done); | ||||
|         QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); | ||||
|  | ||||
|         if (create) { | ||||
| @@ -2032,7 +2096,7 @@ static int coroutine_fn sd_co_rw_vector(void *p) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, create, | ||||
|         add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, | ||||
|                         acb->aiocb_type); | ||||
|     done: | ||||
|         offset = 0; | ||||
| @@ -2112,9 +2176,9 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) | ||||
|     acb->aio_done_func = sd_finish_aiocb; | ||||
|  | ||||
|     aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), | ||||
|                             0, 0, 0, 0, 0); | ||||
|                             0, 0, 0, false, 0, 0); | ||||
|     QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); | ||||
|     add_aio_request(s, aio_req, NULL, 0, false, acb->aiocb_type); | ||||
|     add_aio_request(s, aio_req, NULL, 0, acb->aiocb_type); | ||||
|  | ||||
|     qemu_coroutine_yield(); | ||||
|     return acb->ret; | ||||
| @@ -2122,6 +2186,7 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) | ||||
|  | ||||
| static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     BDRVSheepdogState *s = bs->opaque; | ||||
|     int ret, fd; | ||||
|     uint32_t new_vid; | ||||
| @@ -2149,32 +2214,37 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) | ||||
|     strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag)); | ||||
|     /* we don't need to update entire object */ | ||||
|     datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id); | ||||
|     inode = g_malloc(datalen); | ||||
|  | ||||
|     /* refresh inode. */ | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         ret = fd; | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id), | ||||
|                        s->inode.nr_copies, datalen, 0, false, s->cache_flags); | ||||
|     ret = write_object(fd, s->aio_context, (char *)&s->inode, | ||||
|                        vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies, | ||||
|                        datalen, 0, false, s->cache_flags); | ||||
|     if (ret < 0) { | ||||
|         error_report("failed to write snapshot's inode."); | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     ret = do_sd_create(s, &new_vid, 1); | ||||
|     ret = do_sd_create(s, &new_vid, 1, &local_err); | ||||
|     if (ret < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         error_report("failed to create inode for snapshot. %s", | ||||
|                      strerror(errno)); | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     inode = (SheepdogInode *)g_malloc(datalen); | ||||
|  | ||||
|     ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid), | ||||
|                       s->inode.nr_copies, datalen, 0, s->cache_flags); | ||||
|     ret = read_object(fd, s->aio_context, (char *)inode, | ||||
|                       vid_to_vdi_oid(new_vid), s->inode.nr_copies, datalen, 0, | ||||
|                       s->cache_flags); | ||||
|  | ||||
|     if (ret < 0) { | ||||
|         error_report("failed to read new inode info. %s", strerror(errno)); | ||||
| @@ -2186,6 +2256,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) | ||||
|             s->inode.name, s->inode.snap_id, s->inode.vdi_id); | ||||
|  | ||||
| cleanup: | ||||
|     g_free(inode); | ||||
|     closesocket(fd); | ||||
|     return ret; | ||||
| } | ||||
| @@ -2249,6 +2320,7 @@ static int sd_snapshot_delete(BlockDriverState *bs, | ||||
|  | ||||
| static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     BDRVSheepdogState *s = bs->opaque; | ||||
|     SheepdogReq req; | ||||
|     int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long); | ||||
| @@ -2263,8 +2335,10 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) | ||||
|  | ||||
|     vdi_inuse = g_malloc(max); | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         ret = fd; | ||||
|         goto out; | ||||
|     } | ||||
| @@ -2277,7 +2351,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) | ||||
|     req.opcode = SD_OP_READ_VDIS; | ||||
|     req.data_length = max; | ||||
|  | ||||
|     ret = do_req(fd, (SheepdogReq *)&req, vdi_inuse, &wlen, &rlen); | ||||
|     ret = do_req(fd, s->aio_context, (SheepdogReq *)&req, | ||||
|                  vdi_inuse, &wlen, &rlen); | ||||
|  | ||||
|     closesocket(fd); | ||||
|     if (ret) { | ||||
| @@ -2290,8 +2365,10 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) | ||||
|     hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT); | ||||
|     start_nr = hval & (SD_NR_VDIS - 1); | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         ret = fd; | ||||
|         goto out; | ||||
|     } | ||||
| @@ -2302,7 +2379,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) | ||||
|         } | ||||
|  | ||||
|         /* we don't need to read entire object */ | ||||
|         ret = read_object(fd, (char *)&inode, vid_to_vdi_oid(vid), | ||||
|         ret = read_object(fd, s->aio_context, (char *)&inode, | ||||
|                           vid_to_vdi_oid(vid), | ||||
|                           0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0, | ||||
|                           s->cache_flags); | ||||
|  | ||||
| @@ -2341,6 +2419,7 @@ out: | ||||
| static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, | ||||
|                                 int64_t pos, int size, int load) | ||||
| { | ||||
|     Error *local_err = NULL; | ||||
|     bool create; | ||||
|     int fd, ret = 0, remaining = size; | ||||
|     unsigned int data_len; | ||||
| @@ -2349,8 +2428,10 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, | ||||
|     uint32_t vdi_index; | ||||
|     uint32_t vdi_id = load ? s->inode.parent_vdi_id : s->inode.vdi_id; | ||||
|  | ||||
|     fd = connect_to_sdog(s); | ||||
|     fd = connect_to_sdog(s, &local_err); | ||||
|     if (fd < 0) { | ||||
|         error_report("%s", error_get_pretty(local_err));; | ||||
|         error_free(local_err); | ||||
|         return fd; | ||||
|     } | ||||
|  | ||||
| @@ -2364,11 +2445,11 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, | ||||
|  | ||||
|         create = (offset == 0); | ||||
|         if (load) { | ||||
|             ret = read_object(fd, (char *)data, vmstate_oid, | ||||
|             ret = read_object(fd, s->aio_context, (char *)data, vmstate_oid, | ||||
|                               s->inode.nr_copies, data_len, offset, | ||||
|                               s->cache_flags); | ||||
|         } else { | ||||
|             ret = write_object(fd, (char *)data, vmstate_oid, | ||||
|             ret = write_object(fd, s->aio_context, (char *)data, vmstate_oid, | ||||
|                                s->inode.nr_copies, data_len, offset, create, | ||||
|                                s->cache_flags); | ||||
|         } | ||||
| @@ -2541,6 +2622,9 @@ static BlockDriver bdrv_sheepdog = { | ||||
|     .bdrv_save_vmstate  = sd_save_vmstate, | ||||
|     .bdrv_load_vmstate  = sd_load_vmstate, | ||||
|  | ||||
|     .bdrv_detach_aio_context = sd_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = sd_attach_aio_context, | ||||
|  | ||||
|     .create_options = sd_create_options, | ||||
| }; | ||||
|  | ||||
| @@ -2571,6 +2655,9 @@ static BlockDriver bdrv_sheepdog_tcp = { | ||||
|     .bdrv_save_vmstate  = sd_save_vmstate, | ||||
|     .bdrv_load_vmstate  = sd_load_vmstate, | ||||
|  | ||||
|     .bdrv_detach_aio_context = sd_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = sd_attach_aio_context, | ||||
|  | ||||
|     .create_options = sd_create_options, | ||||
| }; | ||||
|  | ||||
| @@ -2601,6 +2688,9 @@ static BlockDriver bdrv_sheepdog_unix = { | ||||
|     .bdrv_save_vmstate  = sd_save_vmstate, | ||||
|     .bdrv_load_vmstate  = sd_load_vmstate, | ||||
|  | ||||
|     .bdrv_detach_aio_context = sd_detach_aio_context, | ||||
|     .bdrv_attach_aio_context = sd_attach_aio_context, | ||||
|  | ||||
|     .create_options = sd_create_options, | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										187
									
								
								block/ssh.c
									
									
									
									
									
								
							
							
						
						
									
										187
									
								
								block/ssh.c
									
									
									
									
									
								
							| @@ -106,30 +106,59 @@ static void ssh_state_free(BDRVSSHState *s) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Wrappers around error_report which make sure to dump as much | ||||
|  * information from libssh2 as possible. | ||||
|  */ | ||||
| static void GCC_FMT_ATTR(2, 3) | ||||
| session_error_report(BDRVSSHState *s, const char *fs, ...) | ||||
| static void GCC_FMT_ATTR(3, 4) | ||||
| session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...) | ||||
| { | ||||
|     va_list args; | ||||
|     char *msg; | ||||
|  | ||||
|     va_start(args, fs); | ||||
|     error_vprintf(fs, args); | ||||
|     msg = g_strdup_vprintf(fs, args); | ||||
|     va_end(args); | ||||
|  | ||||
|     if ((s)->session) { | ||||
|     if (s->session) { | ||||
|         char *ssh_err; | ||||
|         int ssh_err_code; | ||||
|  | ||||
|         libssh2_session_last_error((s)->session, &ssh_err, NULL, 0); | ||||
|         /* This is not an errno.  See <libssh2.h>. */ | ||||
|         ssh_err_code = libssh2_session_last_errno((s)->session); | ||||
|  | ||||
|         error_printf(": %s (libssh2 error code: %d)", ssh_err, ssh_err_code); | ||||
|         ssh_err_code = libssh2_session_last_error(s->session, | ||||
|                                                   &ssh_err, NULL, 0); | ||||
|         error_setg(errp, "%s: %s (libssh2 error code: %d)", | ||||
|                    msg, ssh_err, ssh_err_code); | ||||
|     } else { | ||||
|         error_setg(errp, "%s", msg); | ||||
|     } | ||||
|     g_free(msg); | ||||
| } | ||||
|  | ||||
| static void GCC_FMT_ATTR(3, 4) | ||||
| sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...) | ||||
| { | ||||
|     va_list args; | ||||
|     char *msg; | ||||
|  | ||||
|     va_start(args, fs); | ||||
|     msg = g_strdup_vprintf(fs, args); | ||||
|     va_end(args); | ||||
|     error_printf("\n"); | ||||
|  | ||||
|     if (s->sftp) { | ||||
|         char *ssh_err; | ||||
|         int ssh_err_code; | ||||
|         unsigned long sftp_err_code; | ||||
|  | ||||
|         /* This is not an errno.  See <libssh2.h>. */ | ||||
|         ssh_err_code = libssh2_session_last_error(s->session, | ||||
|                                                   &ssh_err, NULL, 0); | ||||
|         /* See <libssh2_sftp.h>. */ | ||||
|         sftp_err_code = libssh2_sftp_last_error((s)->sftp); | ||||
|  | ||||
|         error_setg(errp, | ||||
|                    "%s: %s (libssh2 error code: %d, sftp error code: %lu)", | ||||
|                    msg, ssh_err, ssh_err_code, sftp_err_code); | ||||
|     } else { | ||||
|         error_setg(errp, "%s", msg); | ||||
|     } | ||||
|     g_free(msg); | ||||
| } | ||||
|  | ||||
| static void GCC_FMT_ATTR(2, 3) | ||||
| @@ -145,9 +174,9 @@ sftp_error_report(BDRVSSHState *s, const char *fs, ...) | ||||
|         int ssh_err_code; | ||||
|         unsigned long sftp_err_code; | ||||
|  | ||||
|         libssh2_session_last_error((s)->session, &ssh_err, NULL, 0); | ||||
|         /* This is not an errno.  See <libssh2.h>. */ | ||||
|         ssh_err_code = libssh2_session_last_errno((s)->session); | ||||
|         ssh_err_code = libssh2_session_last_error(s->session, | ||||
|                                                   &ssh_err, NULL, 0); | ||||
|         /* See <libssh2_sftp.h>. */ | ||||
|         sftp_err_code = libssh2_sftp_last_error((s)->sftp); | ||||
|  | ||||
| @@ -243,7 +272,7 @@ static void ssh_parse_filename(const char *filename, QDict *options, | ||||
| } | ||||
|  | ||||
| static int check_host_key_knownhosts(BDRVSSHState *s, | ||||
|                                      const char *host, int port) | ||||
|                                      const char *host, int port, Error **errp) | ||||
| { | ||||
|     const char *home; | ||||
|     char *knh_file = NULL; | ||||
| @@ -257,14 +286,15 @@ static int check_host_key_knownhosts(BDRVSSHState *s, | ||||
|     hostkey = libssh2_session_hostkey(s->session, &len, &type); | ||||
|     if (!hostkey) { | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "failed to read remote host key"); | ||||
|         session_error_setg(errp, s, "failed to read remote host key"); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     knh = libssh2_knownhost_init(s->session); | ||||
|     if (!knh) { | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "failed to initialize known hosts support"); | ||||
|         session_error_setg(errp, s, | ||||
|                            "failed to initialize known hosts support"); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
| @@ -289,21 +319,23 @@ static int check_host_key_knownhosts(BDRVSSHState *s, | ||||
|         break; | ||||
|     case LIBSSH2_KNOWNHOST_CHECK_MISMATCH: | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "host key does not match the one in known_hosts (found key %s)", | ||||
|                              found->key); | ||||
|         session_error_setg(errp, s, | ||||
|                       "host key does not match the one in known_hosts" | ||||
|                       " (found key %s)", found->key); | ||||
|         goto out; | ||||
|     case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND: | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "no host key was found in known_hosts"); | ||||
|         session_error_setg(errp, s, "no host key was found in known_hosts"); | ||||
|         goto out; | ||||
|     case LIBSSH2_KNOWNHOST_CHECK_FAILURE: | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "failure matching the host key with known_hosts"); | ||||
|         session_error_setg(errp, s, | ||||
|                       "failure matching the host key with known_hosts"); | ||||
|         goto out; | ||||
|     default: | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "unknown error matching the host key with known_hosts (%d)", | ||||
|                              r); | ||||
|         session_error_setg(errp, s, "unknown error matching the host key" | ||||
|                       " with known_hosts (%d)", r); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
| @@ -358,20 +390,20 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len, | ||||
|  | ||||
| static int | ||||
| check_host_key_hash(BDRVSSHState *s, const char *hash, | ||||
|                     int hash_type, size_t fingerprint_len) | ||||
|                     int hash_type, size_t fingerprint_len, Error **errp) | ||||
| { | ||||
|     const char *fingerprint; | ||||
|  | ||||
|     fingerprint = libssh2_hostkey_hash(s->session, hash_type); | ||||
|     if (!fingerprint) { | ||||
|         session_error_report(s, "failed to read remote host key"); | ||||
|         session_error_setg(errp, s, "failed to read remote host key"); | ||||
|         return -EINVAL; | ||||
|     } | ||||
|  | ||||
|     if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len, | ||||
|                            hash) != 0) { | ||||
|         error_report("remote host key does not match host_key_check '%s'", | ||||
|                      hash); | ||||
|         error_setg(errp, "remote host key does not match host_key_check '%s'", | ||||
|                    hash); | ||||
|         return -EPERM; | ||||
|     } | ||||
|  | ||||
| @@ -379,7 +411,7 @@ check_host_key_hash(BDRVSSHState *s, const char *hash, | ||||
| } | ||||
|  | ||||
| static int check_host_key(BDRVSSHState *s, const char *host, int port, | ||||
|                           const char *host_key_check) | ||||
|                           const char *host_key_check, Error **errp) | ||||
| { | ||||
|     /* host_key_check=no */ | ||||
|     if (strcmp(host_key_check, "no") == 0) { | ||||
| @@ -389,25 +421,25 @@ static int check_host_key(BDRVSSHState *s, const char *host, int port, | ||||
|     /* host_key_check=md5:xx:yy:zz:... */ | ||||
|     if (strncmp(host_key_check, "md5:", 4) == 0) { | ||||
|         return check_host_key_hash(s, &host_key_check[4], | ||||
|                                    LIBSSH2_HOSTKEY_HASH_MD5, 16); | ||||
|                                    LIBSSH2_HOSTKEY_HASH_MD5, 16, errp); | ||||
|     } | ||||
|  | ||||
|     /* host_key_check=sha1:xx:yy:zz:... */ | ||||
|     if (strncmp(host_key_check, "sha1:", 5) == 0) { | ||||
|         return check_host_key_hash(s, &host_key_check[5], | ||||
|                                    LIBSSH2_HOSTKEY_HASH_SHA1, 20); | ||||
|                                    LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp); | ||||
|     } | ||||
|  | ||||
|     /* host_key_check=yes */ | ||||
|     if (strcmp(host_key_check, "yes") == 0) { | ||||
|         return check_host_key_knownhosts(s, host, port); | ||||
|         return check_host_key_knownhosts(s, host, port, errp); | ||||
|     } | ||||
|  | ||||
|     error_report("unknown host_key_check setting (%s)", host_key_check); | ||||
|     error_setg(errp, "unknown host_key_check setting (%s)", host_key_check); | ||||
|     return -EINVAL; | ||||
| } | ||||
|  | ||||
| static int authenticate(BDRVSSHState *s, const char *user) | ||||
| static int authenticate(BDRVSSHState *s, const char *user, Error **errp) | ||||
| { | ||||
|     int r, ret; | ||||
|     const char *userauthlist; | ||||
| @@ -418,7 +450,8 @@ static int authenticate(BDRVSSHState *s, const char *user) | ||||
|     userauthlist = libssh2_userauth_list(s->session, user, strlen(user)); | ||||
|     if (strstr(userauthlist, "publickey") == NULL) { | ||||
|         ret = -EPERM; | ||||
|         error_report("remote server does not support \"publickey\" authentication"); | ||||
|         error_setg(errp, | ||||
|                 "remote server does not support \"publickey\" authentication"); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
| @@ -426,17 +459,18 @@ static int authenticate(BDRVSSHState *s, const char *user) | ||||
|     agent = libssh2_agent_init(s->session); | ||||
|     if (!agent) { | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "failed to initialize ssh-agent support"); | ||||
|         session_error_setg(errp, s, "failed to initialize ssh-agent support"); | ||||
|         goto out; | ||||
|     } | ||||
|     if (libssh2_agent_connect(agent)) { | ||||
|         ret = -ECONNREFUSED; | ||||
|         session_error_report(s, "failed to connect to ssh-agent"); | ||||
|         session_error_setg(errp, s, "failed to connect to ssh-agent"); | ||||
|         goto out; | ||||
|     } | ||||
|     if (libssh2_agent_list_identities(agent)) { | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "failed requesting identities from ssh-agent"); | ||||
|         session_error_setg(errp, s, | ||||
|                            "failed requesting identities from ssh-agent"); | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
| @@ -447,7 +481,8 @@ static int authenticate(BDRVSSHState *s, const char *user) | ||||
|         } | ||||
|         if (r < 0) { | ||||
|             ret = -EINVAL; | ||||
|             session_error_report(s, "failed to obtain identity from ssh-agent"); | ||||
|             session_error_setg(errp, s, | ||||
|                                "failed to obtain identity from ssh-agent"); | ||||
|             goto out; | ||||
|         } | ||||
|         r = libssh2_agent_userauth(agent, user, identity); | ||||
| @@ -461,8 +496,8 @@ static int authenticate(BDRVSSHState *s, const char *user) | ||||
|     } | ||||
|  | ||||
|     ret = -EPERM; | ||||
|     error_report("failed to authenticate using publickey authentication " | ||||
|                  "and the identities held by your ssh-agent"); | ||||
|     error_setg(errp, "failed to authenticate using publickey authentication " | ||||
|                "and the identities held by your ssh-agent"); | ||||
|  | ||||
|  out: | ||||
|     if (agent != NULL) { | ||||
| @@ -476,10 +511,9 @@ static int authenticate(BDRVSSHState *s, const char *user) | ||||
| } | ||||
|  | ||||
| static int connect_to_ssh(BDRVSSHState *s, QDict *options, | ||||
|                           int ssh_flags, int creat_mode) | ||||
|                           int ssh_flags, int creat_mode, Error **errp) | ||||
| { | ||||
|     int r, ret; | ||||
|     Error *err = NULL; | ||||
|     const char *host, *user, *path, *host_key_check; | ||||
|     int port; | ||||
|  | ||||
| @@ -498,6 +532,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, | ||||
|     } else { | ||||
|         user = g_get_user_name(); | ||||
|         if (!user) { | ||||
|             error_setg_errno(errp, errno, "Can't get user name"); | ||||
|             ret = -errno; | ||||
|             goto err; | ||||
|         } | ||||
| @@ -514,11 +549,9 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, | ||||
|     s->hostport = g_strdup_printf("%s:%d", host, port); | ||||
|  | ||||
|     /* Open the socket and connect. */ | ||||
|     s->sock = inet_connect(s->hostport, &err); | ||||
|     if (err != NULL) { | ||||
|     s->sock = inet_connect(s->hostport, errp); | ||||
|     if (s->sock < 0) { | ||||
|         ret = -errno; | ||||
|         qerror_report_err(err); | ||||
|         error_free(err); | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
| @@ -526,7 +559,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, | ||||
|     s->session = libssh2_session_init(); | ||||
|     if (!s->session) { | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "failed to initialize libssh2 session"); | ||||
|         session_error_setg(errp, s, "failed to initialize libssh2 session"); | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
| @@ -537,18 +570,18 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, | ||||
|     r = libssh2_session_handshake(s->session, s->sock); | ||||
|     if (r != 0) { | ||||
|         ret = -EINVAL; | ||||
|         session_error_report(s, "failed to establish SSH session"); | ||||
|         session_error_setg(errp, s, "failed to establish SSH session"); | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
|     /* Check the remote host's key against known_hosts. */ | ||||
|     ret = check_host_key(s, host, port, host_key_check); | ||||
|     ret = check_host_key(s, host, port, host_key_check, errp); | ||||
|     if (ret < 0) { | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
|     /* Authenticate. */ | ||||
|     ret = authenticate(s, user); | ||||
|     ret = authenticate(s, user, errp); | ||||
|     if (ret < 0) { | ||||
|         goto err; | ||||
|     } | ||||
| @@ -556,7 +589,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, | ||||
|     /* Start SFTP. */ | ||||
|     s->sftp = libssh2_sftp_init(s->session); | ||||
|     if (!s->sftp) { | ||||
|         session_error_report(s, "failed to initialize sftp handle"); | ||||
|         session_error_setg(errp, s, "failed to initialize sftp handle"); | ||||
|         ret = -EINVAL; | ||||
|         goto err; | ||||
|     } | ||||
| @@ -566,14 +599,14 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options, | ||||
|             path, ssh_flags, creat_mode); | ||||
|     s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode); | ||||
|     if (!s->sftp_handle) { | ||||
|         session_error_report(s, "failed to open remote file '%s'", path); | ||||
|         session_error_setg(errp, s, "failed to open remote file '%s'", path); | ||||
|         ret = -EINVAL; | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
|     r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs); | ||||
|     if (r < 0) { | ||||
|         sftp_error_report(s, "failed to read file attributes"); | ||||
|         sftp_error_setg(errp, s, "failed to read file attributes"); | ||||
|         return -EINVAL; | ||||
|     } | ||||
|  | ||||
| @@ -623,7 +656,7 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags, | ||||
|     } | ||||
|  | ||||
|     /* Start up SSH. */ | ||||
|     ret = connect_to_ssh(s, options, ssh_flags, 0); | ||||
|     ret = connect_to_ssh(s, options, ssh_flags, 0, errp); | ||||
|     if (ret < 0) { | ||||
|         goto err; | ||||
|     } | ||||
| @@ -655,7 +688,6 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options, | ||||
|                       Error **errp) | ||||
| { | ||||
|     int r, ret; | ||||
|     Error *local_err = NULL; | ||||
|     int64_t total_size = 0; | ||||
|     QDict *uri_options = NULL; | ||||
|     BDRVSSHState s; | ||||
| @@ -674,17 +706,16 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options, | ||||
|     DPRINTF("total_size=%" PRIi64, total_size); | ||||
|  | ||||
|     uri_options = qdict_new(); | ||||
|     r = parse_uri(filename, uri_options, &local_err); | ||||
|     r = parse_uri(filename, uri_options, errp); | ||||
|     if (r < 0) { | ||||
|         qerror_report_err(local_err); | ||||
|         error_free(local_err); | ||||
|         ret = r; | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     r = connect_to_ssh(&s, uri_options, | ||||
|                        LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE| | ||||
|                        LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, 0644); | ||||
|                        LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, | ||||
|                        0644, errp); | ||||
|     if (r < 0) { | ||||
|         ret = r; | ||||
|         goto out; | ||||
| @@ -694,7 +725,7 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options, | ||||
|         libssh2_sftp_seek64(s.sftp_handle, total_size-1); | ||||
|         r2 = libssh2_sftp_write(s.sftp_handle, c, 1); | ||||
|         if (r2 < 0) { | ||||
|             sftp_error_report(&s, "truncate failed"); | ||||
|             sftp_error_setg(errp, &s, "truncate failed"); | ||||
|             ret = -EINVAL; | ||||
|             goto out; | ||||
|         } | ||||
| @@ -742,7 +773,7 @@ static void restart_coroutine(void *opaque) | ||||
|     qemu_coroutine_enter(co, NULL); | ||||
| } | ||||
|  | ||||
| static coroutine_fn void set_fd_handler(BDRVSSHState *s) | ||||
| static coroutine_fn void set_fd_handler(BDRVSSHState *s, BlockDriverState *bs) | ||||
| { | ||||
|     int r; | ||||
|     IOHandler *rd_handler = NULL, *wr_handler = NULL; | ||||
| @@ -760,24 +791,26 @@ static coroutine_fn void set_fd_handler(BDRVSSHState *s) | ||||
|     DPRINTF("s->sock=%d rd_handler=%p wr_handler=%p", s->sock, | ||||
|             rd_handler, wr_handler); | ||||
|  | ||||
|     qemu_aio_set_fd_handler(s->sock, rd_handler, wr_handler, co); | ||||
|     aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, | ||||
|                        rd_handler, wr_handler, co); | ||||
| } | ||||
|  | ||||
| static coroutine_fn void clear_fd_handler(BDRVSSHState *s) | ||||
| static coroutine_fn void clear_fd_handler(BDRVSSHState *s, | ||||
|                                           BlockDriverState *bs) | ||||
| { | ||||
|     DPRINTF("s->sock=%d", s->sock); | ||||
|     qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL); | ||||
|     aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, NULL, NULL, NULL); | ||||
| } | ||||
|  | ||||
| /* A non-blocking call returned EAGAIN, so yield, ensuring the | ||||
|  * handlers are set up so that we'll be rescheduled when there is an | ||||
|  * interesting event on the socket. | ||||
|  */ | ||||
| static coroutine_fn void co_yield(BDRVSSHState *s) | ||||
| static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs) | ||||
| { | ||||
|     set_fd_handler(s); | ||||
|     set_fd_handler(s, bs); | ||||
|     qemu_coroutine_yield(); | ||||
|     clear_fd_handler(s); | ||||
|     clear_fd_handler(s, bs); | ||||
| } | ||||
|  | ||||
| /* SFTP has a function `libssh2_sftp_seek64' which seeks to a position | ||||
| @@ -807,7 +840,7 @@ static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags) | ||||
|     } | ||||
| } | ||||
|  | ||||
| static coroutine_fn int ssh_read(BDRVSSHState *s, | ||||
| static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs, | ||||
|                                  int64_t offset, size_t size, | ||||
|                                  QEMUIOVector *qiov) | ||||
| { | ||||
| @@ -840,7 +873,7 @@ static coroutine_fn int ssh_read(BDRVSSHState *s, | ||||
|         DPRINTF("sftp_read returned %zd", r); | ||||
|  | ||||
|         if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) { | ||||
|             co_yield(s); | ||||
|             co_yield(s, bs); | ||||
|             goto again; | ||||
|         } | ||||
|         if (r < 0) { | ||||
| @@ -875,14 +908,14 @@ static coroutine_fn int ssh_co_readv(BlockDriverState *bs, | ||||
|     int ret; | ||||
|  | ||||
|     qemu_co_mutex_lock(&s->lock); | ||||
|     ret = ssh_read(s, sector_num * BDRV_SECTOR_SIZE, | ||||
|     ret = ssh_read(s, bs, sector_num * BDRV_SECTOR_SIZE, | ||||
|                    nb_sectors * BDRV_SECTOR_SIZE, qiov); | ||||
|     qemu_co_mutex_unlock(&s->lock); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int ssh_write(BDRVSSHState *s, | ||||
| static int ssh_write(BDRVSSHState *s, BlockDriverState *bs, | ||||
|                      int64_t offset, size_t size, | ||||
|                      QEMUIOVector *qiov) | ||||
| { | ||||
| @@ -910,7 +943,7 @@ static int ssh_write(BDRVSSHState *s, | ||||
|         DPRINTF("sftp_write returned %zd", r); | ||||
|  | ||||
|         if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) { | ||||
|             co_yield(s); | ||||
|             co_yield(s, bs); | ||||
|             goto again; | ||||
|         } | ||||
|         if (r < 0) { | ||||
| @@ -929,7 +962,7 @@ static int ssh_write(BDRVSSHState *s, | ||||
|          */ | ||||
|         if (r == 0) { | ||||
|             ssh_seek(s, offset + written, SSH_SEEK_WRITE|SSH_SEEK_FORCE); | ||||
|             co_yield(s); | ||||
|             co_yield(s, bs); | ||||
|             goto again; | ||||
|         } | ||||
|  | ||||
| @@ -957,7 +990,7 @@ static coroutine_fn int ssh_co_writev(BlockDriverState *bs, | ||||
|     int ret; | ||||
|  | ||||
|     qemu_co_mutex_lock(&s->lock); | ||||
|     ret = ssh_write(s, sector_num * BDRV_SECTOR_SIZE, | ||||
|     ret = ssh_write(s, bs, sector_num * BDRV_SECTOR_SIZE, | ||||
|                     nb_sectors * BDRV_SECTOR_SIZE, qiov); | ||||
|     qemu_co_mutex_unlock(&s->lock); | ||||
|  | ||||
| @@ -978,7 +1011,7 @@ static void unsafe_flush_warning(BDRVSSHState *s, const char *what) | ||||
|  | ||||
| #ifdef HAS_LIBSSH2_SFTP_FSYNC | ||||
|  | ||||
| static coroutine_fn int ssh_flush(BDRVSSHState *s) | ||||
| static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs) | ||||
| { | ||||
|     int r; | ||||
|  | ||||
| @@ -986,7 +1019,7 @@ static coroutine_fn int ssh_flush(BDRVSSHState *s) | ||||
|  again: | ||||
|     r = libssh2_sftp_fsync(s->sftp_handle); | ||||
|     if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) { | ||||
|         co_yield(s); | ||||
|         co_yield(s, bs); | ||||
|         goto again; | ||||
|     } | ||||
|     if (r == LIBSSH2_ERROR_SFTP_PROTOCOL && | ||||
| @@ -1008,7 +1041,7 @@ static coroutine_fn int ssh_co_flush(BlockDriverState *bs) | ||||
|     int ret; | ||||
|  | ||||
|     qemu_co_mutex_lock(&s->lock); | ||||
|     ret = ssh_flush(s); | ||||
|     ret = ssh_flush(s, bs); | ||||
|     qemu_co_mutex_unlock(&s->lock); | ||||
|  | ||||
|     return ret; | ||||
|   | ||||
| @@ -60,7 +60,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base, | ||||
|     /* Must assign before bdrv_delete() to prevent traversing dangling pointer | ||||
|      * while we delete backing image instances. | ||||
|      */ | ||||
|     top->backing_hd = base; | ||||
|     bdrv_set_backing_hd(top, base); | ||||
|  | ||||
|     while (intermediate) { | ||||
|         BlockDriverState *unused; | ||||
| @@ -72,7 +72,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base, | ||||
|  | ||||
|         unused = intermediate; | ||||
|         intermediate = intermediate->backing_hd; | ||||
|         unused->backing_hd = NULL; | ||||
|         bdrv_set_backing_hd(unused, NULL); | ||||
|         bdrv_unref(unused); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -239,7 +239,6 @@ static void vdi_header_to_le(VdiHeader *header) | ||||
|     cpu_to_le32s(&header->block_extra); | ||||
|     cpu_to_le32s(&header->blocks_in_image); | ||||
|     cpu_to_le32s(&header->blocks_allocated); | ||||
|     cpu_to_le32s(&header->blocks_allocated); | ||||
|     uuid_convert(header->uuid_image); | ||||
|     uuid_convert(header->uuid_last_snap); | ||||
|     uuid_convert(header->uuid_link); | ||||
|   | ||||
							
								
								
									
										31
									
								
								block/vmdk.c
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								block/vmdk.c
									
									
									
									
									
								
							| @@ -1534,7 +1534,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, | ||||
|     int ret, i; | ||||
|     BlockDriverState *bs = NULL; | ||||
|     VMDK4Header header; | ||||
|     Error *local_err; | ||||
|     Error *local_err = NULL; | ||||
|     uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count; | ||||
|     uint32_t *gd_buf = NULL; | ||||
|     int gd_buf_size; | ||||
| @@ -1700,7 +1700,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, | ||||
| { | ||||
|     int idx = 0; | ||||
|     BlockDriverState *new_bs = NULL; | ||||
|     Error *local_err; | ||||
|     Error *local_err = NULL; | ||||
|     char *desc = NULL; | ||||
|     int64_t total_size = 0, filesize; | ||||
|     const char *adapter_type = NULL; | ||||
| @@ -1881,7 +1881,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, | ||||
|     } else { | ||||
|         ret = bdrv_create_file(filename, options, &local_err); | ||||
|         if (ret < 0) { | ||||
|             error_setg_errno(errp, -ret, "Could not create image file"); | ||||
|             error_propagate(errp, local_err); | ||||
|             goto exit; | ||||
|         } | ||||
|     } | ||||
| @@ -1889,7 +1889,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, | ||||
|     ret = bdrv_open(&new_bs, filename, NULL, NULL, | ||||
|                     BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); | ||||
|     if (ret < 0) { | ||||
|         error_setg_errno(errp, -ret, "Could not write description"); | ||||
|         error_propagate(errp, local_err); | ||||
|         goto exit; | ||||
|     } | ||||
|     ret = bdrv_pwrite(new_bs, desc_offset, desc, desc_len); | ||||
| @@ -2096,6 +2096,27 @@ static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void vmdk_detach_aio_context(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVVmdkState *s = bs->opaque; | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < s->num_extents; i++) { | ||||
|         bdrv_detach_aio_context(s->extents[i].file); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void vmdk_attach_aio_context(BlockDriverState *bs, | ||||
|                                     AioContext *new_context) | ||||
| { | ||||
|     BDRVVmdkState *s = bs->opaque; | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < s->num_extents; i++) { | ||||
|         bdrv_attach_aio_context(s->extents[i].file, new_context); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static QEMUOptionParameter vmdk_create_options[] = { | ||||
|     { | ||||
|         .name = BLOCK_OPT_SIZE, | ||||
| @@ -2153,6 +2174,8 @@ static BlockDriver bdrv_vmdk = { | ||||
|     .bdrv_get_specific_info       = vmdk_get_specific_info, | ||||
|     .bdrv_refresh_limits          = vmdk_refresh_limits, | ||||
|     .bdrv_get_info                = vmdk_get_info, | ||||
|     .bdrv_detach_aio_context      = vmdk_detach_aio_context, | ||||
|     .bdrv_attach_aio_context      = vmdk_attach_aio_context, | ||||
|  | ||||
|     .create_options               = vmdk_create_options, | ||||
| }; | ||||
|   | ||||
| @@ -787,7 +787,9 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) | ||||
| 	    s->current_mapping->path=buffer; | ||||
| 	    s->current_mapping->read_only = | ||||
| 		(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0; | ||||
| 	} | ||||
|         } else { | ||||
|             g_free(buffer); | ||||
|         } | ||||
|     } | ||||
|     closedir(dir); | ||||
|  | ||||
| @@ -831,7 +833,8 @@ static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num) | ||||
| } | ||||
|  | ||||
| static int init_directories(BDRVVVFATState* s, | ||||
|                             const char *dirname, int heads, int secs) | ||||
|                             const char *dirname, int heads, int secs, | ||||
|                             Error **errp) | ||||
| { | ||||
|     bootsector_t* bootsector; | ||||
|     mapping_t* mapping; | ||||
| @@ -892,8 +895,8 @@ static int init_directories(BDRVVVFATState* s, | ||||
|         if (mapping->mode & MODE_DIRECTORY) { | ||||
| 	    mapping->begin = cluster; | ||||
| 	    if(read_directory(s, i)) { | ||||
| 		fprintf(stderr, "Could not read directory %s\n", | ||||
| 			mapping->path); | ||||
|                 error_setg(errp, "Could not read directory %s", | ||||
|                            mapping->path); | ||||
| 		return -1; | ||||
| 	    } | ||||
| 	    mapping = array_get(&(s->mapping), i); | ||||
| @@ -919,9 +922,10 @@ static int init_directories(BDRVVVFATState* s, | ||||
| 	cluster = mapping->end; | ||||
|  | ||||
| 	if(cluster > s->cluster_count) { | ||||
| 	    fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n", | ||||
| 		    s->fat_type, s->sector_count / 2000.0); | ||||
| 	    return -EINVAL; | ||||
|             error_setg(errp, | ||||
|                        "Directory does not fit in FAT%d (capacity %.2f MB)", | ||||
|                        s->fat_type, s->sector_count / 2000.0); | ||||
|             return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* fix fat for entry */ | ||||
| @@ -979,7 +983,7 @@ static int init_directories(BDRVVVFATState* s, | ||||
| static BDRVVVFATState *vvv = NULL; | ||||
| #endif | ||||
|  | ||||
| static int enable_write_target(BDRVVVFATState *s); | ||||
| static int enable_write_target(BDRVVVFATState *s, Error **errp); | ||||
| static int is_consistent(BDRVVVFATState *s); | ||||
|  | ||||
| static void vvfat_rebind(BlockDriverState *bs) | ||||
| @@ -1160,7 +1164,7 @@ DLOG(if (stderr == NULL) { | ||||
|     s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1); | ||||
|  | ||||
|     if (qemu_opt_get_bool(opts, "rw", false)) { | ||||
|         ret = enable_write_target(s); | ||||
|         ret = enable_write_target(s, errp); | ||||
|         if (ret < 0) { | ||||
|             goto fail; | ||||
|         } | ||||
| @@ -1169,7 +1173,7 @@ DLOG(if (stderr == NULL) { | ||||
|  | ||||
|     bs->total_sectors = cyls * heads * secs; | ||||
|  | ||||
|     if (init_directories(s, dirname, heads, secs)) { | ||||
|     if (init_directories(s, dirname, heads, secs, errp)) { | ||||
|         ret = -EIO; | ||||
|         goto fail; | ||||
|     } | ||||
| @@ -1864,7 +1868,7 @@ static int check_directory_consistency(BDRVVVFATState *s, | ||||
|  | ||||
| 	if (s->used_clusters[cluster_num] & USED_ANY) { | ||||
| 	    fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num); | ||||
| 	    return 0; | ||||
|             goto fail; | ||||
| 	} | ||||
| 	s->used_clusters[cluster_num] = USED_DIRECTORY; | ||||
|  | ||||
| @@ -2904,11 +2908,10 @@ static BlockDriver vvfat_write_target = { | ||||
|     .bdrv_close         = write_target_close, | ||||
| }; | ||||
|  | ||||
| static int enable_write_target(BDRVVVFATState *s) | ||||
| static int enable_write_target(BDRVVVFATState *s, Error **errp) | ||||
| { | ||||
|     BlockDriver *bdrv_qcow; | ||||
|     QEMUOptionParameter *options; | ||||
|     Error *local_err = NULL; | ||||
|     int ret; | ||||
|     int size = sector2cluster(s, s->sector_count); | ||||
|     s->used_clusters = calloc(size, 1); | ||||
| @@ -2918,6 +2921,7 @@ static int enable_write_target(BDRVVVFATState *s) | ||||
|     s->qcow_filename = g_malloc(1024); | ||||
|     ret = get_tmp_filename(s->qcow_filename, 1024); | ||||
|     if (ret < 0) { | ||||
|         error_setg_errno(errp, -ret, "can't create temporary file"); | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
| @@ -2926,20 +2930,17 @@ static int enable_write_target(BDRVVVFATState *s) | ||||
|     set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512); | ||||
|     set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:"); | ||||
|  | ||||
|     ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, &local_err); | ||||
|     ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, errp); | ||||
|     free_option_parameters(options); | ||||
|     if (ret < 0) { | ||||
|         qerror_report_err(local_err); | ||||
|         error_free(local_err); | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
|     s->qcow = NULL; | ||||
|     ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL, | ||||
|             BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow, | ||||
|             &local_err); | ||||
|                     BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, | ||||
|                     bdrv_qcow, errp); | ||||
|     if (ret < 0) { | ||||
|         qerror_report_err(local_err); | ||||
|         error_free(local_err); | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
| @@ -2947,7 +2948,7 @@ static int enable_write_target(BDRVVVFATState *s) | ||||
|     unlink(s->qcow_filename); | ||||
| #endif | ||||
|  | ||||
|     s->bs->backing_hd = bdrv_new("", &error_abort); | ||||
|     bdrv_set_backing_hd(s->bs, bdrv_new("", &error_abort)); | ||||
|     s->bs->backing_hd->drv = &vvfat_write_target; | ||||
|     s->bs->backing_hd->opaque = g_malloc(sizeof(void*)); | ||||
|     *(void**)s->bs->backing_hd->opaque = s; | ||||
|   | ||||
| @@ -40,6 +40,7 @@ struct QEMUWin32AIOState { | ||||
|     HANDLE hIOCP; | ||||
|     EventNotifier e; | ||||
|     int count; | ||||
|     bool is_aio_context_attached; | ||||
| }; | ||||
|  | ||||
| typedef struct QEMUWin32AIOCB { | ||||
| @@ -114,7 +115,7 @@ static void win32_aio_cancel(BlockDriverAIOCB *blockacb) | ||||
|      * wait for completion. | ||||
|      */ | ||||
|     while (!HasOverlappedIoCompleted(&waiocb->ov)) { | ||||
|         qemu_aio_wait(); | ||||
|         aio_poll(bdrv_get_aio_context(blockacb->bs), true); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -180,6 +181,20 @@ int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile) | ||||
|     } | ||||
| } | ||||
|  | ||||
| void win32_aio_detach_aio_context(QEMUWin32AIOState *aio, | ||||
|                                   AioContext *old_context) | ||||
| { | ||||
|     aio_set_event_notifier(old_context, &aio->e, NULL); | ||||
|     aio->is_aio_context_attached = false; | ||||
| } | ||||
|  | ||||
| void win32_aio_attach_aio_context(QEMUWin32AIOState *aio, | ||||
|                                   AioContext *new_context) | ||||
| { | ||||
|     aio->is_aio_context_attached = true; | ||||
|     aio_set_event_notifier(new_context, &aio->e, win32_aio_completion_cb); | ||||
| } | ||||
|  | ||||
| QEMUWin32AIOState *win32_aio_init(void) | ||||
| { | ||||
|     QEMUWin32AIOState *s; | ||||
| @@ -194,8 +209,6 @@ QEMUWin32AIOState *win32_aio_init(void) | ||||
|         goto out_close_efd; | ||||
|     } | ||||
|  | ||||
|     qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb); | ||||
|  | ||||
|     return s; | ||||
|  | ||||
| out_close_efd: | ||||
| @@ -204,3 +217,11 @@ out_free_state: | ||||
|     g_free(s); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| void win32_aio_cleanup(QEMUWin32AIOState *aio) | ||||
| { | ||||
|     assert(!aio->is_aio_context_attached); | ||||
|     CloseHandle(aio->hIOCP); | ||||
|     event_notifier_cleanup(&aio->e); | ||||
|     g_free(aio); | ||||
| } | ||||
|   | ||||
| @@ -27,8 +27,8 @@ static void nbd_accept(void *opaque) | ||||
|     socklen_t addr_len = sizeof(addr); | ||||
|  | ||||
|     int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); | ||||
|     if (fd >= 0) { | ||||
|         nbd_client_new(NULL, fd, nbd_client_put); | ||||
|     if (fd >= 0 && !nbd_client_new(NULL, fd, nbd_client_put)) { | ||||
|         close(fd); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										47
									
								
								blockdev.c
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								blockdev.c
									
									
									
									
									
								
							| @@ -34,7 +34,6 @@ | ||||
| #include "hw/block/block.h" | ||||
| #include "block/blockjob.h" | ||||
| #include "monitor/monitor.h" | ||||
| #include "qapi/qmp/qerror.h" | ||||
| #include "qemu/option.h" | ||||
| #include "qemu/config-file.h" | ||||
| #include "qapi/qmp/types.h" | ||||
| @@ -352,7 +351,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, | ||||
|     opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error); | ||||
|     if (error) { | ||||
|         error_propagate(errp, error); | ||||
|         return NULL; | ||||
|         goto err_no_opts; | ||||
|     } | ||||
|  | ||||
|     qemu_opts_absorb_qdict(opts, bs_opts, &error); | ||||
| @@ -565,8 +564,9 @@ bdrv_new_err: | ||||
|     g_free(dinfo->id); | ||||
|     g_free(dinfo); | ||||
| early_err: | ||||
|     QDECREF(bs_opts); | ||||
|     qemu_opts_del(opts); | ||||
| err_no_opts: | ||||
|     QDECREF(bs_opts); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| @@ -730,7 +730,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) | ||||
|                                    &error_abort); | ||||
|     qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err); | ||||
|     if (local_err) { | ||||
|         qerror_report_err(local_err); | ||||
|         error_report("%s", error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         goto fail; | ||||
|     } | ||||
| @@ -940,9 +940,10 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) | ||||
|  | ||||
|     /* Actual block device init: Functionality shared with blockdev-add */ | ||||
|     dinfo = blockdev_init(filename, bs_opts, &local_err); | ||||
|     bs_opts = NULL; | ||||
|     if (dinfo == NULL) { | ||||
|         if (local_err) { | ||||
|             qerror_report_err(local_err); | ||||
|             error_report("%s", error_get_pretty(local_err)); | ||||
|             error_free(local_err); | ||||
|         } | ||||
|         goto fail; | ||||
| @@ -977,6 +978,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) | ||||
|  | ||||
| fail: | ||||
|     qemu_opts_del(legacy_opts); | ||||
|     QDECREF(bs_opts); | ||||
|     return dinfo; | ||||
| } | ||||
|  | ||||
| @@ -1334,8 +1336,8 @@ static void external_snapshot_prepare(BlkTransactionState *common, | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (bdrv_in_use(state->old_bs)) { | ||||
|         error_set(errp, QERR_DEVICE_IN_USE, device); | ||||
|     if (bdrv_op_is_blocked(state->old_bs, | ||||
|                            BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -1557,8 +1559,7 @@ exit: | ||||
|  | ||||
| static void eject_device(BlockDriverState *bs, int force, Error **errp) | ||||
| { | ||||
|     if (bdrv_in_use(bs)) { | ||||
|         error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs)); | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) { | ||||
|         return; | ||||
|     } | ||||
|     if (!bdrv_dev_has_removable_media(bs)) { | ||||
| @@ -1702,6 +1703,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, | ||||
| { | ||||
|     ThrottleConfig cfg; | ||||
|     BlockDriverState *bs; | ||||
|     AioContext *aio_context; | ||||
|  | ||||
|     bs = bdrv_find(device); | ||||
|     if (!bs) { | ||||
| @@ -1745,6 +1747,9 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     aio_context = bdrv_get_aio_context(bs); | ||||
|     aio_context_acquire(aio_context); | ||||
|  | ||||
|     if (!bs->io_limits_enabled && throttle_enabled(&cfg)) { | ||||
|         bdrv_io_limits_enable(bs); | ||||
|     } else if (bs->io_limits_enabled && !throttle_enabled(&cfg)) { | ||||
| @@ -1754,20 +1759,24 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, | ||||
|     if (bs->io_limits_enabled) { | ||||
|         bdrv_set_io_limits(bs, &cfg); | ||||
|     } | ||||
|  | ||||
|     aio_context_release(aio_context); | ||||
| } | ||||
|  | ||||
| int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) | ||||
| { | ||||
|     const char *id = qdict_get_str(qdict, "id"); | ||||
|     BlockDriverState *bs; | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     bs = bdrv_find(id); | ||||
|     if (!bs) { | ||||
|         qerror_report(QERR_DEVICE_NOT_FOUND, id); | ||||
|         error_report("Device '%s' not found", id); | ||||
|         return -1; | ||||
|     } | ||||
|     if (bdrv_in_use(bs)) { | ||||
|         qerror_report(QERR_DEVICE_IN_USE, id); | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) { | ||||
|         error_report("%s", error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
| @@ -1888,6 +1897,10 @@ void qmp_block_stream(const char *device, bool has_base, | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (base) { | ||||
|         base_bs = bdrv_find_backing_image(bs, base); | ||||
|         if (base_bs == NULL) { | ||||
| @@ -1932,6 +1945,10 @@ void qmp_block_commit(const char *device, | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, errp)) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /* default top_bs is the active layer */ | ||||
|     top_bs = bs; | ||||
|  | ||||
| @@ -2023,8 +2040,7 @@ void qmp_drive_backup(const char *device, const char *target, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (bdrv_in_use(bs)) { | ||||
|         error_set(errp, QERR_DEVICE_IN_USE, device); | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -2157,8 +2173,7 @@ void qmp_drive_mirror(const char *device, const char *target, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (bdrv_in_use(bs)) { | ||||
|         error_set(errp, QERR_DEVICE_IN_USE, device); | ||||
|     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										14
									
								
								blockjob.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								blockjob.c
									
									
									
									
									
								
							| @@ -41,14 +41,16 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs, | ||||
| { | ||||
|     BlockJob *job; | ||||
|  | ||||
|     if (bs->job || bdrv_in_use(bs)) { | ||||
|     if (bs->job) { | ||||
|         error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs)); | ||||
|         return NULL; | ||||
|     } | ||||
|     bdrv_ref(bs); | ||||
|     bdrv_set_in_use(bs, 1); | ||||
|  | ||||
|     job = g_malloc0(driver->instance_size); | ||||
|     error_setg(&job->blocker, "block device is in use by block job: %s", | ||||
|                BlockJobType_lookup[driver->job_type]); | ||||
|     bdrv_op_block_all(bs, job->blocker); | ||||
|  | ||||
|     job->driver        = driver; | ||||
|     job->bs            = bs; | ||||
|     job->cb            = cb; | ||||
| @@ -63,8 +65,9 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs, | ||||
|         block_job_set_speed(job, speed, &local_err); | ||||
|         if (local_err) { | ||||
|             bs->job = NULL; | ||||
|             bdrv_op_unblock_all(bs, job->blocker); | ||||
|             error_free(job->blocker); | ||||
|             g_free(job); | ||||
|             bdrv_set_in_use(bs, 0); | ||||
|             error_propagate(errp, local_err); | ||||
|             return NULL; | ||||
|         } | ||||
| @@ -79,8 +82,9 @@ void block_job_completed(BlockJob *job, int ret) | ||||
|     assert(bs->job == job); | ||||
|     job->cb(job->opaque, ret); | ||||
|     bs->job = NULL; | ||||
|     bdrv_op_unblock_all(bs, job->blocker); | ||||
|     error_free(job->blocker); | ||||
|     g_free(job); | ||||
|     bdrv_set_in_use(bs, 0); | ||||
| } | ||||
|  | ||||
| void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) | ||||
|   | ||||
| @@ -1004,7 +1004,7 @@ int main(int argc, char **argv) | ||||
|  | ||||
| #if defined(TARGET_I386) | ||||
|     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; | ||||
|     env->hflags |= HF_PE_MASK; | ||||
|     env->hflags |= HF_PE_MASK | HF_CPL_MASK; | ||||
|     if (env->features[FEAT_1_EDX] & CPUID_SSE) { | ||||
|         env->cr[4] |= CR4_OSFXSR_MASK; | ||||
|         env->hflags |= HF_OSFXSR_MASK; | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include <string.h> | ||||
|  | ||||
| #include "cpu.h" | ||||
| #include "exec/cpu_ldst.h" | ||||
|  | ||||
| #undef DEBUG_REMAP | ||||
| #ifdef DEBUG_REMAP | ||||
|   | ||||
							
								
								
									
										109
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										109
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -2,26 +2,28 @@ | ||||
| # | ||||
| # qemu configure script (c) 2003 Fabrice Bellard | ||||
| # | ||||
| # set temporary file name | ||||
| if test ! -z "$TMPDIR" ; then | ||||
|     TMPDIR1="${TMPDIR}" | ||||
| elif test ! -z "$TEMPDIR" ; then | ||||
|     TMPDIR1="${TEMPDIR}" | ||||
| else | ||||
|     TMPDIR1="/tmp" | ||||
|  | ||||
| # Temporary directory used for files created while | ||||
| # configure runs. Since it is in the build directory | ||||
| # we can safely blow away any previous version of it | ||||
| # (and we need not jump through hoops to try to delete | ||||
| # it when configure exits.) | ||||
| TMPDIR1="config-temp" | ||||
| rm -rf "${TMPDIR1}" | ||||
| mkdir -p "${TMPDIR1}" | ||||
| if [ $? -ne 0 ]; then | ||||
|     echo "ERROR: failed to create temporary directory" | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c" | ||||
| TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}" | ||||
| TMPB="qemu-conf" | ||||
| TMPC="${TMPDIR1}/${TMPB}.c" | ||||
| TMPO="${TMPDIR1}/${TMPB}.o" | ||||
| TMPCXX="${TMPDIR1}/${TMPB}.cxx" | ||||
| TMPL="${TMPDIR1}/${TMPB}.lo" | ||||
| TMPA="${TMPDIR1}/lib${TMPB}.la" | ||||
| TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe" | ||||
| TMPE="${TMPDIR1}/${TMPB}.exe" | ||||
|  | ||||
| # NB: do not call "exit" in the trap handler; this is buggy with some shells; | ||||
| # see <1285349658-3122-1-git-send-email-loic.minier@linaro.org> | ||||
| trap "rm -f $TMPC $TMPO $TMPCXX $TMPE" EXIT INT QUIT TERM | ||||
| rm -f config.log | ||||
|  | ||||
| # Print a helpful header at the top of config.log | ||||
| @@ -180,6 +182,10 @@ path_of() { | ||||
|     return 1 | ||||
| } | ||||
|  | ||||
| have_backend () { | ||||
|     echo "$trace_backends" | grep "$1" >/dev/null | ||||
| } | ||||
|  | ||||
| # default parameters | ||||
| source_path=`dirname "$0"` | ||||
| cpu="" | ||||
| @@ -291,7 +297,7 @@ pkgversion="" | ||||
| pie="" | ||||
| zero_malloc="" | ||||
| qom_cast_debug="yes" | ||||
| trace_backend="nop" | ||||
| trace_backends="nop" | ||||
| trace_file="trace" | ||||
| spice="" | ||||
| rbd="" | ||||
| @@ -317,7 +323,7 @@ glusterfs_discard="no" | ||||
| glusterfs_zerofill="no" | ||||
| virtio_blk_data_plane="" | ||||
| gtk="" | ||||
| gtkabi="2.0" | ||||
| gtkabi="" | ||||
| vte="" | ||||
| tpm="no" | ||||
| libssh2="" | ||||
| @@ -751,7 +757,10 @@ for opt do | ||||
|   ;; | ||||
|   --target-list=*) target_list="$optarg" | ||||
|   ;; | ||||
|   --enable-trace-backend=*) trace_backend="$optarg" | ||||
|   --enable-trace-backends=*) trace_backends="$optarg" | ||||
|   ;; | ||||
|   # XXX: backwards compatibility | ||||
|   --enable-trace-backend=*) trace_backends="$optarg" | ||||
|   ;; | ||||
|   --with-trace-file=*) trace_file="$optarg" | ||||
|   ;; | ||||
| @@ -1318,7 +1327,7 @@ Advanced options (experts only): | ||||
|   --disable-docs           disable documentation build | ||||
|   --disable-vhost-net      disable vhost-net acceleration support | ||||
|   --enable-vhost-net       enable vhost-net acceleration support | ||||
|   --enable-trace-backend=B Set trace backend | ||||
|   --enable-trace-backends=B Set trace backend | ||||
|                            Available backends: $($python $source_path/scripts/tracetool.py --list-backends) | ||||
|   --with-trace-file=NAME   Full PATH,NAME of file to store traces | ||||
|                            Default:trace-<pid> | ||||
| @@ -1970,8 +1979,21 @@ fi | ||||
| ########################################## | ||||
| # GTK probe | ||||
|  | ||||
| if test "$gtkabi" = ""; then | ||||
|     # The GTK ABI was not specified explicitly, so try whether 2.0 is available. | ||||
|     # Use 3.0 as a fallback if that is available. | ||||
|     if $pkg_config --exists "gtk+-2.0 >= 2.18.0"; then | ||||
|         gtkabi=2.0 | ||||
|     elif $pkg_config --exists "gtk+-3.0 >= 3.0.0"; then | ||||
|         gtkabi=3.0 | ||||
|     else | ||||
|         gtkabi=2.0 | ||||
|     fi | ||||
| fi | ||||
|  | ||||
| if test "$gtk" != "no"; then | ||||
|     gtkpackage="gtk+-$gtkabi" | ||||
|     gtkx11package="gtk+-x11-$gtkabi" | ||||
|     if test "$gtkabi" = "3.0" ; then | ||||
|       gtkversion="3.0.0" | ||||
|     else | ||||
| @@ -1980,10 +2002,13 @@ if test "$gtk" != "no"; then | ||||
|     if $pkg_config --exists "$gtkpackage >= $gtkversion"; then | ||||
|         gtk_cflags=`$pkg_config --cflags $gtkpackage` | ||||
|         gtk_libs=`$pkg_config --libs $gtkpackage` | ||||
|         if $pkg_config --exists "$gtkx11package >= $gtkversion"; then | ||||
|             gtk_libs="$gtk_libs -lX11" | ||||
|         fi | ||||
|         libs_softmmu="$gtk_libs $libs_softmmu" | ||||
|         gtk="yes" | ||||
|     elif test "$gtk" = "yes"; then | ||||
|         feature_not_found "gtk" "Install gtk2 or gtk3 (requires --with-gtkabi=3.0 option to configure) devel" | ||||
|         feature_not_found "gtk" "Install gtk2 or gtk3 devel" | ||||
|     else | ||||
|         gtk="no" | ||||
|     fi | ||||
| @@ -2006,7 +2031,11 @@ if test "$vte" != "no"; then | ||||
|         libs_softmmu="$vte_libs $libs_softmmu" | ||||
|         vte="yes" | ||||
|     elif test "$vte" = "yes"; then | ||||
|         feature_not_found "vte" "Install libvte or libvte-2.90 (requires --with-gtkabi=3.0 option to configure) devel" | ||||
|         if test "$gtkabi" = "3.0"; then | ||||
|             feature_not_found "vte" "Install libvte-2.90 devel" | ||||
|         else | ||||
|             feature_not_found "vte" "Install libvte devel" | ||||
|         fi | ||||
|     else | ||||
|         vte="no" | ||||
|     fi | ||||
| @@ -3648,15 +3677,15 @@ fi | ||||
| ########################################## | ||||
| # check if trace backend exists | ||||
|  | ||||
| $python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend  > /dev/null 2> /dev/null | ||||
| $python "$source_path/scripts/tracetool.py" "--backends=$trace_backends" --check-backends  > /dev/null 2> /dev/null | ||||
| if test "$?" -ne 0 ; then | ||||
|   error_exit "invalid trace backend" \ | ||||
|       "Please choose a supported trace backend." | ||||
|   error_exit "invalid trace backends" \ | ||||
|       "Please choose supported trace backends." | ||||
| fi | ||||
|  | ||||
| ########################################## | ||||
| # For 'ust' backend, test if ust headers are present | ||||
| if test "$trace_backend" = "ust"; then | ||||
| if have_backend "ust"; then | ||||
|   cat > $TMPC << EOF | ||||
| #include <lttng/tracepoint.h> | ||||
| int main(void) { return 0; } | ||||
| @@ -3682,7 +3711,7 @@ fi | ||||
|  | ||||
| ########################################## | ||||
| # For 'dtrace' backend, test if 'dtrace' command is present | ||||
| if test "$trace_backend" = "dtrace"; then | ||||
| if have_backend "dtrace"; then | ||||
|   if ! has 'dtrace' ; then | ||||
|     error_exit "dtrace command is not found in PATH $PATH" | ||||
|   fi | ||||
| @@ -4029,11 +4058,14 @@ fi | ||||
| if test "$pie" = "no" ; then | ||||
|   textseg_addr= | ||||
|   case "$cpu" in | ||||
|     arm | hppa | i386 | m68k | ppc | ppc64 | s390* | sparc | sparc64 | x86_64 | x32) | ||||
|     arm | i386 | ppc* | s390* | sparc* | x86_64 | x32) | ||||
|       # ??? Rationale for choosing this address | ||||
|       textseg_addr=0x60000000 | ||||
|       ;; | ||||
|     mips) | ||||
|       textseg_addr=0x400000 | ||||
|       # A 256M aligned address, high in the address space, with enough | ||||
|       # room for the code_gen_buffer above it before the stack. | ||||
|       textseg_addr=0x60000000 | ||||
|       ;; | ||||
|   esac | ||||
|   if [ -n "$textseg_addr" ]; then | ||||
| @@ -4149,7 +4181,7 @@ echo "uuid support      $uuid" | ||||
| echo "libcap-ng support $cap_ng" | ||||
| echo "vhost-net support $vhost_net" | ||||
| echo "vhost-scsi support $vhost_scsi" | ||||
| echo "Trace backend     $trace_backend" | ||||
| echo "Trace backends    $trace_backends" | ||||
| if test "$trace_backend" = "simple"; then | ||||
| echo "Trace output file $trace_file-<pid>" | ||||
| fi | ||||
| @@ -4643,43 +4675,35 @@ if test "$tpm" = "yes"; then | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| # use default implementation for tracing backend-specific routines | ||||
| trace_default=yes | ||||
| echo "TRACE_BACKEND=$trace_backend" >> $config_host_mak | ||||
| if test "$trace_backend" = "nop"; then | ||||
| echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak | ||||
| if have_backend "nop"; then | ||||
|   echo "CONFIG_TRACE_NOP=y" >> $config_host_mak | ||||
| fi | ||||
| if test "$trace_backend" = "simple"; then | ||||
| if have_backend "simple"; then | ||||
|   echo "CONFIG_TRACE_SIMPLE=y" >> $config_host_mak | ||||
|   trace_default=no | ||||
|   # Set the appropriate trace file. | ||||
|   trace_file="\"$trace_file-\" FMT_pid" | ||||
| fi | ||||
| if test "$trace_backend" = "stderr"; then | ||||
| if have_backend "stderr"; then | ||||
|   echo "CONFIG_TRACE_STDERR=y" >> $config_host_mak | ||||
|   trace_default=no | ||||
| fi | ||||
| if test "$trace_backend" = "ust"; then | ||||
| if have_backend "ust"; then | ||||
|   echo "CONFIG_TRACE_UST=y" >> $config_host_mak | ||||
| fi | ||||
| if test "$trace_backend" = "dtrace"; then | ||||
| if have_backend "dtrace"; then | ||||
|   echo "CONFIG_TRACE_DTRACE=y" >> $config_host_mak | ||||
|   if test "$trace_backend_stap" = "yes" ; then | ||||
|     echo "CONFIG_TRACE_SYSTEMTAP=y" >> $config_host_mak | ||||
|   fi | ||||
| fi | ||||
| if test "$trace_backend" = "ftrace"; then | ||||
| if have_backend "ftrace"; then | ||||
|   if test "$linux" = "yes" ; then | ||||
|     echo "CONFIG_TRACE_FTRACE=y" >> $config_host_mak | ||||
|     trace_default=no | ||||
|   else | ||||
|     feature_not_found "ftrace(trace backend)" "ftrace requires Linux" | ||||
|   fi | ||||
| fi | ||||
| echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak | ||||
| if test "$trace_default" = "yes"; then | ||||
|   echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak | ||||
| fi | ||||
|  | ||||
| if test "$rdma" = "yes" ; then | ||||
|   echo "CONFIG_RDMA=y" >> $config_host_mak | ||||
| @@ -5219,3 +5243,4 @@ printf " '%s'" "$0" "$@" >>config.status | ||||
| echo >>config.status | ||||
| chmod +x config.status | ||||
|  | ||||
| rm -r "$TMPDIR1" | ||||
|   | ||||
							
								
								
									
										33
									
								
								cputlb.c
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								cputlb.c
									
									
									
									
									
								
							| @@ -22,11 +22,13 @@ | ||||
| #include "exec/exec-all.h" | ||||
| #include "exec/memory.h" | ||||
| #include "exec/address-spaces.h" | ||||
| #include "exec/cpu_ldst.h" | ||||
|  | ||||
| #include "exec/cputlb.h" | ||||
|  | ||||
| #include "exec/memory-internal.h" | ||||
| #include "exec/ram_addr.h" | ||||
| #include "tcg/tcg.h" | ||||
|  | ||||
| //#define DEBUG_TLB | ||||
| //#define DEBUG_TLB_CHECK | ||||
| @@ -330,21 +332,36 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) | ||||
|     return qemu_ram_addr_from_host_nofail(p); | ||||
| } | ||||
|  | ||||
| #define MMUSUFFIX _mmu | ||||
|  | ||||
| #define SHIFT 0 | ||||
| #include "softmmu_template.h" | ||||
|  | ||||
| #define SHIFT 1 | ||||
| #include "softmmu_template.h" | ||||
|  | ||||
| #define SHIFT 2 | ||||
| #include "softmmu_template.h" | ||||
|  | ||||
| #define SHIFT 3 | ||||
| #include "softmmu_template.h" | ||||
| #undef MMUSUFFIX | ||||
|  | ||||
| #define MMUSUFFIX _cmmu | ||||
| #undef GETPC | ||||
| #define GETPC() ((uintptr_t)0) | ||||
| #undef GETPC_ADJ | ||||
| #define GETPC_ADJ 0 | ||||
| #undef GETRA | ||||
| #define GETRA() ((uintptr_t)0) | ||||
| #define SOFTMMU_CODE_ACCESS | ||||
|  | ||||
| #define SHIFT 0 | ||||
| #include "exec/softmmu_template.h" | ||||
| #include "softmmu_template.h" | ||||
|  | ||||
| #define SHIFT 1 | ||||
| #include "exec/softmmu_template.h" | ||||
| #include "softmmu_template.h" | ||||
|  | ||||
| #define SHIFT 2 | ||||
| #include "exec/softmmu_template.h" | ||||
| #include "softmmu_template.h" | ||||
|  | ||||
| #define SHIFT 3 | ||||
| #include "exec/softmmu_template.h" | ||||
|  | ||||
| #undef env | ||||
| #include "softmmu_template.h" | ||||
|   | ||||
| @@ -143,12 +143,12 @@ static void dma_bdrv_cb(void *opaque, int ret) | ||||
|  | ||||
|     dbs->acb = NULL; | ||||
|     dbs->sector_num += dbs->iov.size / 512; | ||||
|     dma_bdrv_unmap(dbs); | ||||
|  | ||||
|     if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) { | ||||
|         dma_complete(dbs, ret); | ||||
|         return; | ||||
|     } | ||||
|     dma_bdrv_unmap(dbs); | ||||
|  | ||||
|     while (dbs->sg_cur_index < dbs->sg->nsg) { | ||||
|         cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte; | ||||
|   | ||||
| @@ -6,16 +6,20 @@ host side | ||||
| --------- | ||||
|  | ||||
| First you must compile qemu with a user interface supporting | ||||
| multihead/multiseat and input event routing.  Right now this list is | ||||
| pretty short: sdl2. | ||||
| multihead/multiseat and input event routing.  Right now this | ||||
| list includes sdl2 and gtk (both 2+3): | ||||
|  | ||||
|   ./configure --enable-sdl --with-sdlabi=2.0 | ||||
|  | ||||
| or | ||||
|  | ||||
|   ./configure --enable-gtk | ||||
|  | ||||
|  | ||||
| Next put together the qemu command line: | ||||
|  | ||||
| qemu	-enable-kvm -usb $memory $disk $whatever \ | ||||
| 	-display sdl \ | ||||
| 	-display [ sdl | gtk ] \ | ||||
| 	-vga std \ | ||||
| 	-device usb-tablet | ||||
|  | ||||
| @@ -37,6 +41,20 @@ The "display=video2" sets up the input routing.  Any input coming from | ||||
| the window which belongs to the video.2 display adapter will be routed | ||||
| to these input devices. | ||||
|  | ||||
| The sdl2 ui will start up with two windows, one for each display | ||||
| device.  The gtk ui will start with a single window and each display | ||||
| in a separate tab.  You can either simply switch tabs to switch heads, | ||||
| or use the "View / Detach tab" menu item to move one of the displays | ||||
| to its own window so you can see both display devices side-by-side. | ||||
|  | ||||
| Note on spice: Spice handles multihead just fine.  But it can't do | ||||
| multiseat.  For tablet events the event source is sent to the spice | ||||
| agent.  But qemu can't figure it, so it can't do input routing. | ||||
| Fixing this needs a new or extended input interface between | ||||
| libspice-server and qemu.  For keyboard events it is even worse:  The | ||||
| event source isn't included in the spice protocol, so the wire | ||||
| protocol must be extended to support this. | ||||
|  | ||||
|  | ||||
| guest side | ||||
| ---------- | ||||
| @@ -46,29 +64,37 @@ You need a pretty recent linux guest.  systemd with loginctl.  kernel | ||||
| fully updated for the new kernel though, i.e. the live iso doesn't cut | ||||
| it. | ||||
|  | ||||
| Now we'll have to configure the guest.  Boot and login.  By default | ||||
| all devices belong to seat0.  You can use "loginctl seat-status seat0" | ||||
| to list them all (and to get the sysfs paths for cut+paste).  Now | ||||
| we'll go assign all pci devices connected the pci bridge in slot 12 to | ||||
| a new head: | ||||
| Now we'll have to configure the guest.  Boot and login.  "lspci -vt" | ||||
| should list the pci bridge with the display adapter and usb controller: | ||||
|  | ||||
| loginctl attach seat-qemu \ | ||||
| 	 /sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/drm/card1 | ||||
| loginctl attach seat-qemu \ | ||||
| 	 /sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/graphics/fb1 | ||||
| loginctl attach seat-qemu \ | ||||
| 	 /sys/devices/pci0000:00/0000:00:12.0/0000:01:0f.0/usb2 | ||||
|     [root@fedora ~]# lspci -vt | ||||
|     -[0000:00]-+-00.0  Intel Corporation 440FX - 82441FX PMC [Natoma] | ||||
|                [ ... ] | ||||
|                \-12.0-[01]--+-02.0  Device 1234:1111 | ||||
|                             \-0f.0  NEC Corporation USB 3.0 Host Controller | ||||
|  | ||||
| Use "loginctl seat-status seat-qemu" to check the result.  It isn't | ||||
| needed to assign the usb devices to the head individually, assigning a | ||||
| usb (root) hub will automatically assign all usb devices connected to | ||||
| it too. | ||||
| Good.  Now lets tell the system that the pci bridge and all devices | ||||
| below it belong to a separate seat by dropping a file into | ||||
| /etc/udev/rules.d: | ||||
|  | ||||
| BTW: loginctl writes udev rules to /etc/udev/rules.d to make these | ||||
| device assignments permanent, so you need to do this only once. | ||||
|     [root@fedora ~]# cat /etc/udev/rules.d/70-qemu-autoseat.rules | ||||
|     SUBSYSTEMS=="pci", DEVPATH=="*/0000:00:12.0", TAG+="seat", ENV{ID_AUTOSEAT}="1" | ||||
|  | ||||
| Now simply restart gdm (rebooting will do too), and a login screen | ||||
| should show up on the second head. | ||||
| Reboot.  System should come up with two seats.  With loginctl you can | ||||
| check the configuration: | ||||
|  | ||||
|     [root@fedora ~]# loginctl list-seats | ||||
|     SEAT | ||||
|     seat0 | ||||
|     seat-pci-pci-0000_00_12_0 | ||||
|  | ||||
|     2 seats listed. | ||||
|  | ||||
| You can use "loginctl seat-status seat-pci-pci-0000_00_12_0" to list | ||||
| the devices attached to the seat. | ||||
|  | ||||
| Background info is here: | ||||
|   http://www.freedesktop.org/wiki/Software/systemd/multiseat/ | ||||
|  | ||||
| Enjoy! | ||||
|  | ||||
|   | ||||
| @@ -107,8 +107,9 @@ in the description of a field. | ||||
|  | ||||
|          96 -  99:  refcount_order | ||||
|                     Describes the width of a reference count block entry (width | ||||
|                     in bits = 1 << refcount_order). For version 2 images, the | ||||
|                     order is always assumed to be 4 (i.e. the width is 16 bits). | ||||
|                     in bits: refcount_bits = 1 << refcount_order). For version 2 | ||||
|                     images, the order is always assumed to be 4 | ||||
|                     (i.e. refcount_bits = 16). | ||||
|  | ||||
|         100 - 103:  header_length | ||||
|                     Length of the header structure in bytes. For version 2 | ||||
|   | ||||
| @@ -9,7 +9,7 @@ for debugging, profiling, and observing execution. | ||||
|  | ||||
| 1. Build with the 'simple' trace backend: | ||||
|  | ||||
|     ./configure --enable-trace-backend=simple | ||||
|     ./configure --enable-trace-backends=simple | ||||
|     make | ||||
|  | ||||
| 2. Create a file with the events you want to trace: | ||||
| @@ -142,7 +142,7 @@ script. | ||||
| The trace backend is chosen at configure time and only one trace backend can | ||||
| be built into the binary: | ||||
|  | ||||
|     ./configure --trace-backend=simple | ||||
|     ./configure --trace-backends=simple | ||||
|  | ||||
| For a list of supported trace backends, try ./configure --help or see below. | ||||
|  | ||||
|   | ||||
| @@ -35,7 +35,8 @@ which will return a dictionary containing: | ||||
|  | ||||
|   o A key named last-update, which contains the last stats update | ||||
|     timestamp in seconds. Since this timestamp is generated by the host, | ||||
|     a buggy guest can't influence its value | ||||
|     a buggy guest can't influence its value. The value is 0 if the guest | ||||
|     has not updated the stats (yet). | ||||
|  | ||||
| It's also important to note the following: | ||||
|  | ||||
| @@ -49,7 +50,7 @@ It's also important to note the following: | ||||
|  | ||||
|  - Polling can be enabled even if the guest doesn't have stats support | ||||
|    or the balloon driver wasn't loaded in the guest. If this is the case | ||||
|    and stats are queried, an error will be returned | ||||
|    and stats are queried, last-update will be 0. | ||||
|  | ||||
|  - The polling timer is only re-armed when the guest responds to the | ||||
|    statistics request. This means that if a (buggy) guest doesn't ever | ||||
|   | ||||
| @@ -34,7 +34,7 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) | ||||
|  | ||||
|     len = strlen(s->tag); | ||||
|     cfg = g_malloc0(sizeof(struct virtio_9p_config) + len); | ||||
|     stw_raw(&cfg->tag_len, len); | ||||
|     stw_p(&cfg->tag_len, len); | ||||
|     /* We don't copy the terminating null to config space */ | ||||
|     memcpy(cfg->tag, s->tag, len); | ||||
|     memcpy(config, cfg, s->config_size); | ||||
|   | ||||
| @@ -43,13 +43,13 @@ static int clipper_pci_map_irq(PCIDevice *d, int irq_num) | ||||
|     return (slot + 1) * 4 + irq_num; | ||||
| } | ||||
|  | ||||
| static void clipper_init(QEMUMachineInitArgs *args) | ||||
| static void clipper_init(MachineState *machine) | ||||
| { | ||||
|     ram_addr_t ram_size = args->ram_size; | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     ram_addr_t ram_size = machine->ram_size; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     AlphaCPU *cpus[4]; | ||||
|     PCIBus *pci_bus; | ||||
|     ISABus *isa_bus; | ||||
|   | ||||
| @@ -23,12 +23,12 @@ static struct arm_boot_info collie_binfo = { | ||||
|     .ram_size = 0x20000000, | ||||
| }; | ||||
|  | ||||
| static void collie_init(QEMUMachineInitArgs *args) | ||||
| static void collie_init(MachineState *machine) | ||||
| { | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     StrongARMState *s; | ||||
|     DriveInfo *dinfo; | ||||
|     MemoryRegion *sysmem = get_system_memory(); | ||||
|   | ||||
| @@ -30,7 +30,7 @@ typedef struct CubieBoardState { | ||||
|     MemoryRegion sdram; | ||||
| } CubieBoardState; | ||||
|  | ||||
| static void cubieboard_init(QEMUMachineInitArgs *args) | ||||
| static void cubieboard_init(MachineState *machine) | ||||
| { | ||||
|     CubieBoardState *s = g_new(CubieBoardState, 1); | ||||
|     Error *err = NULL; | ||||
| @@ -63,14 +63,15 @@ static void cubieboard_init(QEMUMachineInitArgs *args) | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram", args->ram_size); | ||||
|     memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram", | ||||
|                            machine->ram_size); | ||||
|     vmstate_register_ram_global(&s->sdram); | ||||
|     memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE, | ||||
|                                 &s->sdram); | ||||
|  | ||||
|     cubieboard_binfo.ram_size = args->ram_size; | ||||
|     cubieboard_binfo.kernel_filename = args->kernel_filename; | ||||
|     cubieboard_binfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     cubieboard_binfo.ram_size = machine->ram_size; | ||||
|     cubieboard_binfo.kernel_filename = machine->kernel_filename; | ||||
|     cubieboard_binfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     arm_load_kernel(&s->a10->cpu, &cubieboard_binfo); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -143,7 +143,7 @@ static DigicBoard digic4_board_canon_a1100 = { | ||||
|     .rom1_def_filename = "canon-a1100-rom1.bin", | ||||
| }; | ||||
|  | ||||
| static void canon_a1100_init(QEMUMachineInitArgs *args) | ||||
| static void canon_a1100_init(MachineState *machine) | ||||
| { | ||||
|     digic4_board_init(&digic4_board_canon_a1100); | ||||
| } | ||||
|   | ||||
| @@ -94,7 +94,7 @@ static void lan9215_init(uint32_t base, qemu_irq irq) | ||||
|     } | ||||
| } | ||||
|  | ||||
| static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, | ||||
| static Exynos4210State *exynos4_boards_init_common(MachineState *machine, | ||||
|                                                    Exynos4BoardType board_type) | ||||
| { | ||||
|     if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) { | ||||
| @@ -108,9 +108,9 @@ static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, | ||||
|     exynos4_board_binfo.board_id = exynos4_board_id[board_type]; | ||||
|     exynos4_board_binfo.smp_bootreg_addr = | ||||
|             exynos4_board_smp_bootreg_addr[board_type]; | ||||
|     exynos4_board_binfo.kernel_filename = args->kernel_filename; | ||||
|     exynos4_board_binfo.initrd_filename = args->initrd_filename; | ||||
|     exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     exynos4_board_binfo.kernel_filename = machine->kernel_filename; | ||||
|     exynos4_board_binfo.initrd_filename = machine->initrd_filename; | ||||
|     exynos4_board_binfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     exynos4_board_binfo.gic_cpu_if_addr = | ||||
|             EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; | ||||
|  | ||||
| @@ -120,24 +120,24 @@ static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, | ||||
|             " initrd_filename: %s\n", | ||||
|             exynos4_board_ram_size[board_type] / 1048576, | ||||
|             exynos4_board_ram_size[board_type], | ||||
|             args->kernel_filename, | ||||
|             args->kernel_cmdline, | ||||
|             args->initrd_filename); | ||||
|             machine->kernel_filename, | ||||
|             machine->kernel_cmdline, | ||||
|             machine->initrd_filename); | ||||
|  | ||||
|     return exynos4210_init(get_system_memory(), | ||||
|             exynos4_board_ram_size[board_type]); | ||||
| } | ||||
|  | ||||
| static void nuri_init(QEMUMachineInitArgs *args) | ||||
| static void nuri_init(MachineState *machine) | ||||
| { | ||||
|     exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI); | ||||
|     exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI); | ||||
|  | ||||
|     arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); | ||||
| } | ||||
|  | ||||
| static void smdkc210_init(QEMUMachineInitArgs *args) | ||||
| static void smdkc210_init(MachineState *machine) | ||||
| { | ||||
|     Exynos4210State *s = exynos4_boards_init_common(args, | ||||
|     Exynos4210State *s = exynos4_boards_init_common(machine, | ||||
|                                                     EXYNOS4_BOARD_SMDKC210); | ||||
|  | ||||
|     lan9215_init(SMDK_LAN9118_BASE_ADDR, | ||||
|   | ||||
| @@ -46,7 +46,7 @@ | ||||
|  | ||||
| static const int sector_len = 128 * 1024; | ||||
|  | ||||
| static void connex_init(QEMUMachineInitArgs *args) | ||||
| static void connex_init(MachineState *machine) | ||||
| { | ||||
|     PXA2xxState *cpu; | ||||
|     DriveInfo *dinfo; | ||||
| @@ -83,9 +83,9 @@ static void connex_init(QEMUMachineInitArgs *args) | ||||
|                     qdev_get_gpio_in(cpu->gpio, 36)); | ||||
| } | ||||
|  | ||||
| static void verdex_init(QEMUMachineInitArgs *args) | ||||
| static void verdex_init(MachineState *machine) | ||||
| { | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     PXA2xxState *cpu; | ||||
|     DriveInfo *dinfo; | ||||
|     int be; | ||||
|   | ||||
| @@ -199,13 +199,13 @@ enum cxmachines { | ||||
|  * 32-bit host, set the reg value of memory to 0xf7ff00000 in the | ||||
|  * device tree and pass -m 2047 to QEMU. | ||||
|  */ | ||||
| static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) | ||||
| static void calxeda_init(MachineState *machine, enum cxmachines machine_id) | ||||
| { | ||||
|     ram_addr_t ram_size = args->ram_size; | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     ram_addr_t ram_size = machine->ram_size; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     DeviceState *dev = NULL; | ||||
|     SysBusDevice *busdev; | ||||
|     qemu_irq pic[128]; | ||||
| @@ -217,7 +217,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) | ||||
|     char *sysboot_filename; | ||||
|  | ||||
|     if (!cpu_model) { | ||||
|         switch (machine) { | ||||
|         switch (machine_id) { | ||||
|         case CALXEDA_HIGHBANK: | ||||
|             cpu_model = "cortex-a9"; | ||||
|             break; | ||||
| @@ -274,7 +274,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     switch (machine) { | ||||
|     switch (machine_id) { | ||||
|     case CALXEDA_HIGHBANK: | ||||
|         dev = qdev_create(NULL, "l2x0"); | ||||
|         qdev_init_nofail(dev); | ||||
| @@ -359,14 +359,14 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) | ||||
|     arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo); | ||||
| } | ||||
|  | ||||
| static void highbank_init(QEMUMachineInitArgs *args) | ||||
| static void highbank_init(MachineState *machine) | ||||
| { | ||||
|     calxeda_init(args, CALXEDA_HIGHBANK); | ||||
|     calxeda_init(machine, CALXEDA_HIGHBANK); | ||||
| } | ||||
|  | ||||
| static void midway_init(QEMUMachineInitArgs *args) | ||||
| static void midway_init(MachineState *machine) | ||||
| { | ||||
|     calxeda_init(args, CALXEDA_MIDWAY); | ||||
|     calxeda_init(machine, CALXEDA_MIDWAY); | ||||
| } | ||||
|  | ||||
| static QEMUMachine highbank_machine = { | ||||
|   | ||||
| @@ -461,13 +461,13 @@ static struct arm_boot_info integrator_binfo = { | ||||
|     .board_id = 0x113, | ||||
| }; | ||||
|  | ||||
| static void integratorcp_init(QEMUMachineInitArgs *args) | ||||
| static void integratorcp_init(MachineState *machine) | ||||
| { | ||||
|     ram_addr_t ram_size = args->ram_size; | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     ram_addr_t ram_size = machine->ram_size; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     ARMCPU *cpu; | ||||
|     MemoryRegion *address_space_mem = get_system_memory(); | ||||
|     MemoryRegion *ram = g_new(MemoryRegion, 1); | ||||
|   | ||||
							
								
								
									
										12
									
								
								hw/arm/kzm.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								hw/arm/kzm.c
									
									
									
									
									
								
							| @@ -70,13 +70,13 @@ static struct arm_boot_info kzm_binfo = { | ||||
|     .board_id = 1722, | ||||
| }; | ||||
|  | ||||
| static void kzm_init(QEMUMachineInitArgs *args) | ||||
| static void kzm_init(MachineState *machine) | ||||
| { | ||||
|     ram_addr_t ram_size = args->ram_size; | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     ram_addr_t ram_size = machine->ram_size; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     ARMCPU *cpu; | ||||
|     MemoryRegion *address_space_mem = get_system_memory(); | ||||
|     MemoryRegion *ram = g_new(MemoryRegion, 1); | ||||
|   | ||||
| @@ -105,7 +105,7 @@ static struct arm_boot_info mainstone_binfo = { | ||||
| }; | ||||
|  | ||||
| static void mainstone_common_init(MemoryRegion *address_space_mem, | ||||
|                                   QEMUMachineInitArgs *args, | ||||
|                                   MachineState *machine, | ||||
|                                   enum mainstone_model_e model, int arm_id) | ||||
| { | ||||
|     uint32_t sector_len = 256 * 1024; | ||||
| @@ -116,7 +116,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, | ||||
|     int i; | ||||
|     int be; | ||||
|     MemoryRegion *rom = g_new(MemoryRegion, 1); | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|  | ||||
|     if (!cpu_model) | ||||
|         cpu_model = "pxa270-c5"; | ||||
| @@ -175,16 +175,16 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, | ||||
|     smc91c111_init(&nd_table[0], MST_ETH_PHYS, | ||||
|                     qdev_get_gpio_in(mst_irq, ETHERNET_IRQ)); | ||||
|  | ||||
|     mainstone_binfo.kernel_filename = args->kernel_filename; | ||||
|     mainstone_binfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     mainstone_binfo.initrd_filename = args->initrd_filename; | ||||
|     mainstone_binfo.kernel_filename = machine->kernel_filename; | ||||
|     mainstone_binfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     mainstone_binfo.initrd_filename = machine->initrd_filename; | ||||
|     mainstone_binfo.board_id = arm_id; | ||||
|     arm_load_kernel(mpu->cpu, &mainstone_binfo); | ||||
| } | ||||
|  | ||||
| static void mainstone_init(QEMUMachineInitArgs *args) | ||||
| static void mainstone_init(MachineState *machine) | ||||
| { | ||||
|     mainstone_common_init(get_system_memory(), args, mainstone, 0x196); | ||||
|     mainstone_common_init(get_system_memory(), machine, mainstone, 0x196); | ||||
| } | ||||
|  | ||||
| static QEMUMachine mainstone2_machine = { | ||||
|   | ||||
| @@ -1569,12 +1569,12 @@ static struct arm_boot_info musicpal_binfo = { | ||||
|     .board_id = 0x20e, | ||||
| }; | ||||
|  | ||||
| static void musicpal_init(QEMUMachineInitArgs *args) | ||||
| static void musicpal_init(MachineState *machine) | ||||
| { | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     ARMCPU *cpu; | ||||
|     qemu_irq pic[32]; | ||||
|     DeviceState *dev; | ||||
|   | ||||
							
								
								
									
										338
									
								
								hw/arm/nseries.c
									
									
									
									
									
								
							
							
						
						
									
										338
									
								
								hw/arm/nseries.c
									
									
									
									
									
								
							| @@ -239,8 +239,9 @@ static void n800_key_event(void *opaque, int keycode) | ||||
|     int code = s->keymap[keycode & 0x7f]; | ||||
|  | ||||
|     if (code == -1) { | ||||
|         if ((keycode & 0x7f) == RETU_KEYCODE) | ||||
|         if ((keycode & 0x7f) == RETU_KEYCODE) { | ||||
|             retu_key_event(s->retu, !(keycode & 0x80)); | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -280,11 +281,14 @@ static void n800_tsc_kbd_setup(struct n800_s *s) | ||||
|     s->ts.opaque = s->ts.chip->opaque; | ||||
|     s->ts.txrx = tsc210x_txrx; | ||||
|  | ||||
|     for (i = 0; i < 0x80; i ++) | ||||
|     for (i = 0; i < 0x80; i++) { | ||||
|         s->keymap[i] = -1; | ||||
|     for (i = 0; i < 0x10; i ++) | ||||
|         if (n800_keys[i] >= 0) | ||||
|     } | ||||
|     for (i = 0; i < 0x10; i++) { | ||||
|         if (n800_keys[i] >= 0) { | ||||
|             s->keymap[n800_keys[i]] = i; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     qemu_add_kbd_event_handler(n800_key_event, s); | ||||
|  | ||||
| @@ -308,8 +312,9 @@ static void n810_key_event(void *opaque, int keycode) | ||||
|     int code = s->keymap[keycode & 0x7f]; | ||||
|  | ||||
|     if (code == -1) { | ||||
|         if ((keycode & 0x7f) == RETU_KEYCODE) | ||||
|         if ((keycode & 0x7f) == RETU_KEYCODE) { | ||||
|             retu_key_event(s->retu, !(keycode & 0x80)); | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @@ -388,11 +393,14 @@ static void n810_kbd_setup(struct n800_s *s) | ||||
|     qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO); | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < 0x80; i ++) | ||||
|     for (i = 0; i < 0x80; i++) { | ||||
|         s->keymap[i] = -1; | ||||
|     for (i = 0; i < 0x80; i ++) | ||||
|         if (n810_keys[i] > 0) | ||||
|     } | ||||
|     for (i = 0; i < 0x80; i++) { | ||||
|         if (n810_keys[i] > 0) { | ||||
|             s->keymap[n810_keys[i]] = i; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     qemu_add_kbd_event_handler(n810_key_event, s); | ||||
|  | ||||
| @@ -449,17 +457,20 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) | ||||
|     struct mipid_s *s = (struct mipid_s *) opaque; | ||||
|     uint8_t ret; | ||||
|  | ||||
|     if (len > 9) | ||||
|     if (len > 9) { | ||||
|         hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len); | ||||
|     } | ||||
|  | ||||
|     if (s->p >= ARRAY_SIZE(s->resp)) | ||||
|     if (s->p >= ARRAY_SIZE(s->resp)) { | ||||
|         ret = 0; | ||||
|     else | ||||
|         ret = s->resp[s->p ++]; | ||||
|     if (s->pm --> 0) | ||||
|     } else { | ||||
|         ret = s->resp[s->p++]; | ||||
|     } | ||||
|     if (s->pm-- > 0) { | ||||
|         s->param[s->pm] = cmd; | ||||
|     else | ||||
|     } else { | ||||
|         s->cmd = cmd; | ||||
|     } | ||||
|  | ||||
|     switch (s->cmd) { | ||||
|     case 0x00:	/* NOP */ | ||||
| @@ -560,15 +571,17 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) | ||||
|         goto bad_cmd; | ||||
|  | ||||
|     case 0x25:	/* WRCNTR */ | ||||
|         if (s->pm < 0) | ||||
|         if (s->pm < 0) { | ||||
|             s->pm = 1; | ||||
|         } | ||||
|         goto bad_cmd; | ||||
|  | ||||
|     case 0x26:	/* GAMSET */ | ||||
|         if (!s->pm) | ||||
|         if (!s->pm) { | ||||
|             s->gamma = ffs(s->param[0] & 0xf) - 1; | ||||
|         else if (s->pm < 0) | ||||
|         } else if (s->pm < 0) { | ||||
|             s->pm = 1; | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|     case 0x28:	/* DISPOFF */ | ||||
| @@ -591,10 +604,11 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) | ||||
|         s->te = 0; | ||||
|         break; | ||||
|     case 0x35:	/* TEON */ | ||||
|         if (!s->pm) | ||||
|         if (!s->pm) { | ||||
|             s->te = 1; | ||||
|         else if (s->pm < 0) | ||||
|         } else if (s->pm < 0) { | ||||
|             s->pm = 1; | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|     case 0x36:	/* MADCTR */ | ||||
| @@ -613,8 +627,9 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) | ||||
|  | ||||
|     case 0xb0:	/* CLKINT / DISCTL */ | ||||
|     case 0xb1:	/* CLKEXT */ | ||||
|         if (s->pm < 0) | ||||
|         if (s->pm < 0) { | ||||
|             s->pm = 2; | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|     case 0xb4:	/* FRMSEL */ | ||||
| @@ -635,8 +650,9 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) | ||||
|         break; | ||||
|  | ||||
|     case 0xc2:	/* IFMOD */ | ||||
|         if (s->pm < 0) | ||||
|         if (s->pm < 0) { | ||||
|             s->pm = 2; | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|     case 0xc6:	/* PWRCTL */ | ||||
| @@ -834,118 +850,119 @@ static void n800_setup_nolo_tags(void *sram_base) | ||||
|  | ||||
|     strcpy((void *) (p + 8), "F5"); | ||||
|  | ||||
|     stl_raw(p + 10, 0x04f70000); | ||||
|     stl_p(p + 10, 0x04f70000); | ||||
|     strcpy((void *) (p + 9), "RX-34"); | ||||
|  | ||||
|     /* RAM size in MB? */ | ||||
|     stl_raw(p + 12, 0x80); | ||||
|     stl_p(p + 12, 0x80); | ||||
|  | ||||
|     /* Pointer to the list of tags */ | ||||
|     stl_raw(p + 13, OMAP2_SRAM_BASE + 0x9000); | ||||
|     stl_p(p + 13, OMAP2_SRAM_BASE + 0x9000); | ||||
|  | ||||
|     /* The NOLO tags start here */ | ||||
|     p = sram_base + 0x9000; | ||||
| #define ADD_TAG(tag, len)				\ | ||||
|     stw_raw((uint16_t *) p + 0, tag);			\ | ||||
|     stw_raw((uint16_t *) p + 1, len); p ++;		\ | ||||
|     stl_raw(p ++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff)); | ||||
|     stw_p((uint16_t *) p + 0, tag);			\ | ||||
|     stw_p((uint16_t *) p + 1, len); p++;		\ | ||||
|     stl_p(p++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff)); | ||||
|  | ||||
|     /* OMAP STI console? Pin out settings? */ | ||||
|     ADD_TAG(0x6e01, 414); | ||||
|     for (i = 0; i < ARRAY_SIZE(n800_pinout); i ++) | ||||
|         stl_raw(v ++, n800_pinout[i]); | ||||
|     for (i = 0; i < ARRAY_SIZE(n800_pinout); i++) { | ||||
|         stl_p(v++, n800_pinout[i]); | ||||
|     } | ||||
|  | ||||
|     /* Kernel memsize? */ | ||||
|     ADD_TAG(0x6e05, 1); | ||||
|     stl_raw(v ++, 2); | ||||
|     stl_p(v++, 2); | ||||
|  | ||||
|     /* NOLO serial console */ | ||||
|     ADD_TAG(0x6e02, 4); | ||||
|     stl_raw(v ++, XLDR_LL_UART);	/* UART number (1 - 3) */ | ||||
|     stl_p(v++, XLDR_LL_UART);		/* UART number (1 - 3) */ | ||||
|  | ||||
| #if 0 | ||||
|     /* CBUS settings (Retu/AVilma) */ | ||||
|     ADD_TAG(0x6e03, 6); | ||||
|     stw_raw((uint16_t *) v + 0, 65);	/* CBUS GPIO0 */ | ||||
|     stw_raw((uint16_t *) v + 1, 66);	/* CBUS GPIO1 */ | ||||
|     stw_raw((uint16_t *) v + 2, 64);	/* CBUS GPIO2 */ | ||||
|     stw_p((uint16_t *) v + 0, 65);	/* CBUS GPIO0 */ | ||||
|     stw_p((uint16_t *) v + 1, 66);	/* CBUS GPIO1 */ | ||||
|     stw_p((uint16_t *) v + 2, 64);	/* CBUS GPIO2 */ | ||||
|     v += 2; | ||||
| #endif | ||||
|  | ||||
|     /* Nokia ASIC BB5 (Retu/Tahvo) */ | ||||
|     ADD_TAG(0x6e0a, 4); | ||||
|     stw_raw((uint16_t *) v + 0, 111);	/* "Retu" interrupt GPIO */ | ||||
|     stw_raw((uint16_t *) v + 1, 108);	/* "Tahvo" interrupt GPIO */ | ||||
|     v ++; | ||||
|     stw_p((uint16_t *) v + 0, 111);	/* "Retu" interrupt GPIO */ | ||||
|     stw_p((uint16_t *) v + 1, 108);	/* "Tahvo" interrupt GPIO */ | ||||
|     v++; | ||||
|  | ||||
|     /* LCD console? */ | ||||
|     ADD_TAG(0x6e04, 4); | ||||
|     stw_raw((uint16_t *) v + 0, 30);	/* ??? */ | ||||
|     stw_raw((uint16_t *) v + 1, 24);	/* ??? */ | ||||
|     v ++; | ||||
|     stw_p((uint16_t *) v + 0, 30);	/* ??? */ | ||||
|     stw_p((uint16_t *) v + 1, 24);	/* ??? */ | ||||
|     v++; | ||||
|  | ||||
| #if 0 | ||||
|     /* LCD settings */ | ||||
|     ADD_TAG(0x6e06, 2); | ||||
|     stw_raw((uint16_t *) (v ++), 15);	/* ??? */ | ||||
|     stw_p((uint16_t *) (v++), 15);	/* ??? */ | ||||
| #endif | ||||
|  | ||||
|     /* I^2C (Menelaus) */ | ||||
|     ADD_TAG(0x6e07, 4); | ||||
|     stl_raw(v ++, 0x00720000);		/* ??? */ | ||||
|     stl_p(v++, 0x00720000);		/* ??? */ | ||||
|  | ||||
|     /* Unknown */ | ||||
|     ADD_TAG(0x6e0b, 6); | ||||
|     stw_raw((uint16_t *) v + 0, 94);	/* ??? */ | ||||
|     stw_raw((uint16_t *) v + 1, 23);	/* ??? */ | ||||
|     stw_raw((uint16_t *) v + 2, 0);	/* ??? */ | ||||
|     stw_p((uint16_t *) v + 0, 94);	/* ??? */ | ||||
|     stw_p((uint16_t *) v + 1, 23);	/* ??? */ | ||||
|     stw_p((uint16_t *) v + 2, 0);	/* ??? */ | ||||
|     v += 2; | ||||
|  | ||||
|     /* OMAP gpio switch info */ | ||||
|     ADD_TAG(0x6e0c, 80); | ||||
|     strcpy((void *) v, "bat_cover");	v += 3; | ||||
|     stw_raw((uint16_t *) v + 0, 110);	/* GPIO num ??? */ | ||||
|     stw_raw((uint16_t *) v + 1, 1);	/* GPIO num ??? */ | ||||
|     stw_p((uint16_t *) v + 0, 110);	/* GPIO num ??? */ | ||||
|     stw_p((uint16_t *) v + 1, 1);	/* GPIO num ??? */ | ||||
|     v += 2; | ||||
|     strcpy((void *) v, "cam_act");	v += 3; | ||||
|     stw_raw((uint16_t *) v + 0, 95);	/* GPIO num ??? */ | ||||
|     stw_raw((uint16_t *) v + 1, 32);	/* GPIO num ??? */ | ||||
|     stw_p((uint16_t *) v + 0, 95);	/* GPIO num ??? */ | ||||
|     stw_p((uint16_t *) v + 1, 32);	/* GPIO num ??? */ | ||||
|     v += 2; | ||||
|     strcpy((void *) v, "cam_turn");	v += 3; | ||||
|     stw_raw((uint16_t *) v + 0, 12);	/* GPIO num ??? */ | ||||
|     stw_raw((uint16_t *) v + 1, 33);	/* GPIO num ??? */ | ||||
|     stw_p((uint16_t *) v + 0, 12);	/* GPIO num ??? */ | ||||
|     stw_p((uint16_t *) v + 1, 33);	/* GPIO num ??? */ | ||||
|     v += 2; | ||||
|     strcpy((void *) v, "headphone");	v += 3; | ||||
|     stw_raw((uint16_t *) v + 0, 107);	/* GPIO num ??? */ | ||||
|     stw_raw((uint16_t *) v + 1, 17);	/* GPIO num ??? */ | ||||
|     stw_p((uint16_t *) v + 0, 107);	/* GPIO num ??? */ | ||||
|     stw_p((uint16_t *) v + 1, 17);	/* GPIO num ??? */ | ||||
|     v += 2; | ||||
|  | ||||
|     /* Bluetooth */ | ||||
|     ADD_TAG(0x6e0e, 12); | ||||
|     stl_raw(v ++, 0x5c623d01);		/* ??? */ | ||||
|     stl_raw(v ++, 0x00000201);		/* ??? */ | ||||
|     stl_raw(v ++, 0x00000000);		/* ??? */ | ||||
|     stl_p(v++, 0x5c623d01);		/* ??? */ | ||||
|     stl_p(v++, 0x00000201);		/* ??? */ | ||||
|     stl_p(v++, 0x00000000);		/* ??? */ | ||||
|  | ||||
|     /* CX3110x WLAN settings */ | ||||
|     ADD_TAG(0x6e0f, 8); | ||||
|     stl_raw(v ++, 0x00610025);		/* ??? */ | ||||
|     stl_raw(v ++, 0xffff0057);		/* ??? */ | ||||
|     stl_p(v++, 0x00610025);		/* ??? */ | ||||
|     stl_p(v++, 0xffff0057);		/* ??? */ | ||||
|  | ||||
|     /* MMC host settings */ | ||||
|     ADD_TAG(0x6e10, 12); | ||||
|     stl_raw(v ++, 0xffff000f);		/* ??? */ | ||||
|     stl_raw(v ++, 0xffffffff);		/* ??? */ | ||||
|     stl_raw(v ++, 0x00000060);		/* ??? */ | ||||
|     stl_p(v++, 0xffff000f);		/* ??? */ | ||||
|     stl_p(v++, 0xffffffff);		/* ??? */ | ||||
|     stl_p(v++, 0x00000060);		/* ??? */ | ||||
|  | ||||
|     /* OneNAND chip select */ | ||||
|     ADD_TAG(0x6e11, 10); | ||||
|     stl_raw(v ++, 0x00000401);		/* ??? */ | ||||
|     stl_raw(v ++, 0x0002003a);		/* ??? */ | ||||
|     stl_raw(v ++, 0x00000002);		/* ??? */ | ||||
|     stl_p(v++, 0x00000401);		/* ??? */ | ||||
|     stl_p(v++, 0x0002003a);		/* ??? */ | ||||
|     stl_p(v++, 0x00000002);		/* ??? */ | ||||
|  | ||||
|     /* TEA5761 sensor settings */ | ||||
|     ADD_TAG(0x6e12, 2); | ||||
|     stl_raw(v ++, 93);			/* GPIO num ??? */ | ||||
|     stl_p(v++, 93);			/* GPIO num ??? */ | ||||
|  | ||||
| #if 0 | ||||
|     /* Unknown tag */ | ||||
| @@ -956,8 +973,8 @@ static void n800_setup_nolo_tags(void *sram_base) | ||||
| #endif | ||||
|  | ||||
|     /* End of the list */ | ||||
|     stl_raw(p ++, 0x00000000); | ||||
|     stl_raw(p ++, 0x00000000); | ||||
|     stl_p(p++, 0x00000000); | ||||
|     stl_p(p++, 0x00000000); | ||||
| } | ||||
|  | ||||
| /* This task is normally performed by the bootloader.  If we're loading | ||||
| @@ -1032,8 +1049,9 @@ static void n8x0_boot_init(void *opaque) | ||||
|     s->mpu->cpu->env.GE = 0x5; | ||||
|  | ||||
|     /* If the machine has a slided keyboard, open it */ | ||||
|     if (s->kbd) | ||||
|     if (s->kbd) { | ||||
|         qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #define OMAP_TAG_NOKIA_BT	0x4e01 | ||||
| @@ -1119,112 +1137,112 @@ static int n8x0_atag_setup(void *p, int model) | ||||
|  | ||||
|     w = p; | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_UART);		/* u16 tag */ | ||||
|     stw_raw(w ++, 4);				/* u16 len */ | ||||
|     stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */ | ||||
|     w ++; | ||||
|     stw_p(w++, OMAP_TAG_UART);			/* u16 tag */ | ||||
|     stw_p(w++, 4);				/* u16 len */ | ||||
|     stw_p(w++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */ | ||||
|     w++; | ||||
|  | ||||
| #if 0 | ||||
|     stw_raw(w ++, OMAP_TAG_SERIAL_CONSOLE);	/* u16 tag */ | ||||
|     stw_raw(w ++, 4);				/* u16 len */ | ||||
|     stw_raw(w ++, XLDR_LL_UART + 1);		/* u8 console_uart */ | ||||
|     stw_raw(w ++, 115200);			/* u32 console_speed */ | ||||
|     stw_p(w++, OMAP_TAG_SERIAL_CONSOLE);	/* u16 tag */ | ||||
|     stw_p(w++, 4);				/* u16 len */ | ||||
|     stw_p(w++, XLDR_LL_UART + 1);		/* u8 console_uart */ | ||||
|     stw_p(w++, 115200);				/* u32 console_speed */ | ||||
| #endif | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_LCD);		/* u16 tag */ | ||||
|     stw_raw(w ++, 36);				/* u16 len */ | ||||
|     stw_p(w++, OMAP_TAG_LCD);			/* u16 tag */ | ||||
|     stw_p(w++, 36);				/* u16 len */ | ||||
|     strcpy((void *) w, "QEMU LCD panel");	/* char panel_name[16] */ | ||||
|     w += 8; | ||||
|     strcpy((void *) w, "blizzard");		/* char ctrl_name[16] */ | ||||
|     w += 8; | ||||
|     stw_raw(w ++, N810_BLIZZARD_RESET_GPIO);	/* TODO: n800 s16 nreset_gpio */ | ||||
|     stw_raw(w ++, 24);				/* u8 data_lines */ | ||||
|     stw_p(w++, N810_BLIZZARD_RESET_GPIO);	/* TODO: n800 s16 nreset_gpio */ | ||||
|     stw_p(w++, 24);				/* u8 data_lines */ | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_CBUS);		/* u16 tag */ | ||||
|     stw_raw(w ++, 8);				/* u16 len */ | ||||
|     stw_raw(w ++, N8X0_CBUS_CLK_GPIO);		/* s16 clk_gpio */ | ||||
|     stw_raw(w ++, N8X0_CBUS_DAT_GPIO);		/* s16 dat_gpio */ | ||||
|     stw_raw(w ++, N8X0_CBUS_SEL_GPIO);		/* s16 sel_gpio */ | ||||
|     w ++; | ||||
|     stw_p(w++, OMAP_TAG_CBUS);			/* u16 tag */ | ||||
|     stw_p(w++, 8);				/* u16 len */ | ||||
|     stw_p(w++, N8X0_CBUS_CLK_GPIO);		/* s16 clk_gpio */ | ||||
|     stw_p(w++, N8X0_CBUS_DAT_GPIO);		/* s16 dat_gpio */ | ||||
|     stw_p(w++, N8X0_CBUS_SEL_GPIO);		/* s16 sel_gpio */ | ||||
|     w++; | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5);	/* u16 tag */ | ||||
|     stw_raw(w ++, 4);				/* u16 len */ | ||||
|     stw_raw(w ++, N8X0_RETU_GPIO);		/* s16 retu_irq_gpio */ | ||||
|     stw_raw(w ++, N8X0_TAHVO_GPIO);		/* s16 tahvo_irq_gpio */ | ||||
|     stw_p(w++, OMAP_TAG_EM_ASIC_BB5);		/* u16 tag */ | ||||
|     stw_p(w++, 4);				/* u16 len */ | ||||
|     stw_p(w++, N8X0_RETU_GPIO);			/* s16 retu_irq_gpio */ | ||||
|     stw_p(w++, N8X0_TAHVO_GPIO);		/* s16 tahvo_irq_gpio */ | ||||
|  | ||||
|     gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info; | ||||
|     for (; gpiosw->name; gpiosw ++) { | ||||
|         stw_raw(w ++, OMAP_TAG_GPIO_SWITCH);	/* u16 tag */ | ||||
|         stw_raw(w ++, 20);			/* u16 len */ | ||||
|     for (; gpiosw->name; gpiosw++) { | ||||
|         stw_p(w++, OMAP_TAG_GPIO_SWITCH);	/* u16 tag */ | ||||
|         stw_p(w++, 20);				/* u16 len */ | ||||
|         strcpy((void *) w, gpiosw->name);	/* char name[12] */ | ||||
|         w += 6; | ||||
|         stw_raw(w ++, gpiosw->line);		/* u16 gpio */ | ||||
|         stw_raw(w ++, gpiosw->type); | ||||
|         stw_raw(w ++, 0); | ||||
|         stw_raw(w ++, 0); | ||||
|         stw_p(w++, gpiosw->line);		/* u16 gpio */ | ||||
|         stw_p(w++, gpiosw->type); | ||||
|         stw_p(w++, 0); | ||||
|         stw_p(w++, 0); | ||||
|     } | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_NOKIA_BT);		/* u16 tag */ | ||||
|     stw_raw(w ++, 12);				/* u16 len */ | ||||
|     stw_p(w++, OMAP_TAG_NOKIA_BT);		/* u16 tag */ | ||||
|     stw_p(w++, 12);				/* u16 len */ | ||||
|     b = (void *) w; | ||||
|     stb_raw(b ++, 0x01);			/* u8 chip_type	(CSR) */ | ||||
|     stb_raw(b ++, N8X0_BT_WKUP_GPIO);		/* u8 bt_wakeup_gpio */ | ||||
|     stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO);	/* u8 host_wakeup_gpio */ | ||||
|     stb_raw(b ++, N8X0_BT_RESET_GPIO);		/* u8 reset_gpio */ | ||||
|     stb_raw(b ++, BT_UART + 1);			/* u8 bt_uart */ | ||||
|     stb_p(b++, 0x01);				/* u8 chip_type	(CSR) */ | ||||
|     stb_p(b++, N8X0_BT_WKUP_GPIO);		/* u8 bt_wakeup_gpio */ | ||||
|     stb_p(b++, N8X0_BT_HOST_WKUP_GPIO);		/* u8 host_wakeup_gpio */ | ||||
|     stb_p(b++, N8X0_BT_RESET_GPIO);		/* u8 reset_gpio */ | ||||
|     stb_p(b++, BT_UART + 1);			/* u8 bt_uart */ | ||||
|     memcpy(b, &n8x0_bd_addr, 6);		/* u8 bd_addr[6] */ | ||||
|     b += 6; | ||||
|     stb_raw(b ++, 0x02);			/* u8 bt_sysclk (38.4) */ | ||||
|     stb_p(b++, 0x02);				/* u8 bt_sysclk (38.4) */ | ||||
|     w = (void *) b; | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_WLAN_CX3110X);	/* u16 tag */ | ||||
|     stw_raw(w ++, 8);				/* u16 len */ | ||||
|     stw_raw(w ++, 0x25);			/* u8 chip_type */ | ||||
|     stw_raw(w ++, N8X0_WLAN_PWR_GPIO);		/* s16 power_gpio */ | ||||
|     stw_raw(w ++, N8X0_WLAN_IRQ_GPIO);		/* s16 irq_gpio */ | ||||
|     stw_raw(w ++, -1);				/* s16 spi_cs_gpio */ | ||||
|     stw_p(w++, OMAP_TAG_WLAN_CX3110X);		/* u16 tag */ | ||||
|     stw_p(w++, 8);				/* u16 len */ | ||||
|     stw_p(w++, 0x25);				/* u8 chip_type */ | ||||
|     stw_p(w++, N8X0_WLAN_PWR_GPIO);		/* s16 power_gpio */ | ||||
|     stw_p(w++, N8X0_WLAN_IRQ_GPIO);		/* s16 irq_gpio */ | ||||
|     stw_p(w++, -1);				/* s16 spi_cs_gpio */ | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_MMC);		/* u16 tag */ | ||||
|     stw_raw(w ++, 16);				/* u16 len */ | ||||
|     stw_p(w++, OMAP_TAG_MMC);			/* u16 tag */ | ||||
|     stw_p(w++, 16);				/* u16 len */ | ||||
|     if (model == 810) { | ||||
|         stw_raw(w ++, 0x23f);			/* unsigned flags */ | ||||
|         stw_raw(w ++, -1);			/* s16 power_pin */ | ||||
|         stw_raw(w ++, -1);			/* s16 switch_pin */ | ||||
|         stw_raw(w ++, -1);			/* s16 wp_pin */ | ||||
|         stw_raw(w ++, 0x240);			/* unsigned flags */ | ||||
|         stw_raw(w ++, 0xc000);			/* s16 power_pin */ | ||||
|         stw_raw(w ++, 0x0248);			/* s16 switch_pin */ | ||||
|         stw_raw(w ++, 0xc000);			/* s16 wp_pin */ | ||||
|         stw_p(w++, 0x23f);			/* unsigned flags */ | ||||
|         stw_p(w++, -1);				/* s16 power_pin */ | ||||
|         stw_p(w++, -1);				/* s16 switch_pin */ | ||||
|         stw_p(w++, -1);				/* s16 wp_pin */ | ||||
|         stw_p(w++, 0x240);			/* unsigned flags */ | ||||
|         stw_p(w++, 0xc000);			/* s16 power_pin */ | ||||
|         stw_p(w++, 0x0248);			/* s16 switch_pin */ | ||||
|         stw_p(w++, 0xc000);			/* s16 wp_pin */ | ||||
|     } else { | ||||
|         stw_raw(w ++, 0xf);			/* unsigned flags */ | ||||
|         stw_raw(w ++, -1);			/* s16 power_pin */ | ||||
|         stw_raw(w ++, -1);			/* s16 switch_pin */ | ||||
|         stw_raw(w ++, -1);			/* s16 wp_pin */ | ||||
|         stw_raw(w ++, 0);			/* unsigned flags */ | ||||
|         stw_raw(w ++, 0);			/* s16 power_pin */ | ||||
|         stw_raw(w ++, 0);			/* s16 switch_pin */ | ||||
|         stw_raw(w ++, 0);			/* s16 wp_pin */ | ||||
|         stw_p(w++, 0xf);			/* unsigned flags */ | ||||
|         stw_p(w++, -1);				/* s16 power_pin */ | ||||
|         stw_p(w++, -1);				/* s16 switch_pin */ | ||||
|         stw_p(w++, -1);				/* s16 wp_pin */ | ||||
|         stw_p(w++, 0);				/* unsigned flags */ | ||||
|         stw_p(w++, 0);				/* s16 power_pin */ | ||||
|         stw_p(w++, 0);				/* s16 switch_pin */ | ||||
|         stw_p(w++, 0);				/* s16 wp_pin */ | ||||
|     } | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_TEA5761);		/* u16 tag */ | ||||
|     stw_raw(w ++, 4);				/* u16 len */ | ||||
|     stw_raw(w ++, N8X0_TEA5761_CS_GPIO);	/* u16 enable_gpio */ | ||||
|     w ++; | ||||
|     stw_p(w++, OMAP_TAG_TEA5761);		/* u16 tag */ | ||||
|     stw_p(w++, 4);				/* u16 len */ | ||||
|     stw_p(w++, N8X0_TEA5761_CS_GPIO);		/* u16 enable_gpio */ | ||||
|     w++; | ||||
|  | ||||
|     partition = (model == 810) ? n810_part_info : n800_part_info; | ||||
|     for (; partition->name; partition ++) { | ||||
|         stw_raw(w ++, OMAP_TAG_PARTITION);	/* u16 tag */ | ||||
|         stw_raw(w ++, 28);			/* u16 len */ | ||||
|     for (; partition->name; partition++) { | ||||
|         stw_p(w++, OMAP_TAG_PARTITION);		/* u16 tag */ | ||||
|         stw_p(w++, 28);				/* u16 len */ | ||||
|         strcpy((void *) w, partition->name);	/* char name[16] */ | ||||
|         l = (void *) (w + 8); | ||||
|         stl_raw(l ++, partition->size);		/* unsigned int size */ | ||||
|         stl_raw(l ++, partition->offset);	/* unsigned int offset */ | ||||
|         stl_raw(l ++, partition->mask);		/* unsigned int mask_flags */ | ||||
|         stl_p(l++, partition->size);		/* unsigned int size */ | ||||
|         stl_p(l++, partition->offset);		/* unsigned int offset */ | ||||
|         stl_p(l++, partition->mask);		/* unsigned int mask_flags */ | ||||
|         w = (void *) l; | ||||
|     } | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_BOOT_REASON);	/* u16 tag */ | ||||
|     stw_raw(w ++, 12);				/* u16 len */ | ||||
|     stw_p(w++, OMAP_TAG_BOOT_REASON);		/* u16 tag */ | ||||
|     stw_p(w++, 12);				/* u16 len */ | ||||
| #if 0 | ||||
|     strcpy((void *) w, "por");			/* char reason_str[12] */ | ||||
|     strcpy((void *) w, "charger");		/* char reason_str[12] */ | ||||
| @@ -1242,15 +1260,15 @@ static int n8x0_atag_setup(void *p, int model) | ||||
|     w += 6; | ||||
|  | ||||
|     tag = (model == 810) ? "RX-44" : "RX-34"; | ||||
|     stw_raw(w ++, OMAP_TAG_VERSION_STR);	/* u16 tag */ | ||||
|     stw_raw(w ++, 24);				/* u16 len */ | ||||
|     stw_p(w++, OMAP_TAG_VERSION_STR);		/* u16 tag */ | ||||
|     stw_p(w++, 24);				/* u16 len */ | ||||
|     strcpy((void *) w, "product");		/* char component[12] */ | ||||
|     w += 6; | ||||
|     strcpy((void *) w, tag);			/* char version[12] */ | ||||
|     w += 6; | ||||
|  | ||||
|     stw_raw(w ++, OMAP_TAG_VERSION_STR);	/* u16 tag */ | ||||
|     stw_raw(w ++, 24);				/* u16 len */ | ||||
|     stw_p(w++, OMAP_TAG_VERSION_STR);		/* u16 tag */ | ||||
|     stw_p(w++, 24);				/* u16 len */ | ||||
|     strcpy((void *) w, "hw-build");		/* char component[12] */ | ||||
|     w += 6; | ||||
|     strcpy((void *) w, "QEMU "); | ||||
| @@ -1258,8 +1276,8 @@ static int n8x0_atag_setup(void *p, int model) | ||||
|     w += 6; | ||||
|  | ||||
|     tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu"; | ||||
|     stw_raw(w ++, OMAP_TAG_VERSION_STR);	/* u16 tag */ | ||||
|     stw_raw(w ++, 24);				/* u16 len */ | ||||
|     stw_p(w++, OMAP_TAG_VERSION_STR);		/* u16 tag */ | ||||
|     stw_p(w++, 24);				/* u16 len */ | ||||
|     strcpy((void *) w, "nolo");			/* char component[12] */ | ||||
|     w += 6; | ||||
|     strcpy((void *) w, tag);			/* char version[12] */ | ||||
| @@ -1278,14 +1296,14 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p) | ||||
|     return n8x0_atag_setup(p, 810); | ||||
| } | ||||
|  | ||||
| static void n8x0_init(QEMUMachineInitArgs *args, | ||||
| static void n8x0_init(MachineState *machine, | ||||
|                       struct arm_boot_info *binfo, int model) | ||||
| { | ||||
|     MemoryRegion *sysmem = get_system_memory(); | ||||
|     struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); | ||||
|     int sdram_size = binfo->ram_size; | ||||
|  | ||||
|     s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model); | ||||
|     s->mpu = omap2420_mpu_init(sysmem, sdram_size, machine->cpu_model); | ||||
|  | ||||
|     /* Setup peripherals | ||||
|      * | ||||
| @@ -1315,9 +1333,9 @@ static void n8x0_init(QEMUMachineInitArgs *args, | ||||
|     n8x0_gpio_setup(s); | ||||
|     n8x0_nand_setup(s); | ||||
|     n8x0_i2c_setup(s); | ||||
|     if (model == 800) | ||||
|     if (model == 800) { | ||||
|         n800_tsc_kbd_setup(s); | ||||
|     else if (model == 810) { | ||||
|     } else if (model == 810) { | ||||
|         n810_tsc_setup(s); | ||||
|         n810_kbd_setup(s); | ||||
|     } | ||||
| @@ -1329,18 +1347,18 @@ static void n8x0_init(QEMUMachineInitArgs *args, | ||||
|         n8x0_usb_setup(s); | ||||
|     } | ||||
|  | ||||
|     if (args->kernel_filename) { | ||||
|     if (machine->kernel_filename) { | ||||
|         /* Or at the linux loader.  */ | ||||
|         binfo->kernel_filename = args->kernel_filename; | ||||
|         binfo->kernel_cmdline = args->kernel_cmdline; | ||||
|         binfo->initrd_filename = args->initrd_filename; | ||||
|         binfo->kernel_filename = machine->kernel_filename; | ||||
|         binfo->kernel_cmdline = machine->kernel_cmdline; | ||||
|         binfo->initrd_filename = machine->initrd_filename; | ||||
|         arm_load_kernel(s->mpu->cpu, binfo); | ||||
|  | ||||
|         qemu_register_reset(n8x0_boot_init, s); | ||||
|     } | ||||
|  | ||||
|     if (option_rom[0].name && | ||||
|         (args->boot_order[0] == 'n' || !args->kernel_filename)) { | ||||
|         (machine->boot_order[0] == 'n' || !machine->kernel_filename)) { | ||||
|         uint8_t nolo_tags[0x10000]; | ||||
|         /* No, wait, better start at the ROM.  */ | ||||
|         s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; | ||||
| @@ -1382,14 +1400,14 @@ static struct arm_boot_info n810_binfo = { | ||||
|     .atag_board = n810_atag_setup, | ||||
| }; | ||||
|  | ||||
| static void n800_init(QEMUMachineInitArgs *args) | ||||
| static void n800_init(MachineState *machine) | ||||
| { | ||||
|     return n8x0_init(args, &n800_binfo, 800); | ||||
|     return n8x0_init(machine, &n800_binfo, 800); | ||||
| } | ||||
|  | ||||
| static void n810_init(QEMUMachineInitArgs *args) | ||||
| static void n810_init(MachineState *machine) | ||||
| { | ||||
|     return n8x0_init(args, &n810_binfo, 810); | ||||
|     return n8x0_init(machine, &n810_binfo, 810); | ||||
| } | ||||
|  | ||||
| static QEMUMachine n800_machine = { | ||||
|   | ||||
| @@ -98,7 +98,7 @@ static struct arm_boot_info sx1_binfo = { | ||||
|     .board_id = 0x265, | ||||
| }; | ||||
|  | ||||
| static void sx1_init(QEMUMachineInitArgs *args, const int version) | ||||
| static void sx1_init(MachineState *machine, const int version) | ||||
| { | ||||
|     struct omap_mpu_state_s *mpu; | ||||
|     MemoryRegion *address_space = get_system_memory(); | ||||
| @@ -118,7 +118,8 @@ static void sx1_init(QEMUMachineInitArgs *args, const int version) | ||||
|         flash_size = flash2_size; | ||||
|     } | ||||
|  | ||||
|     mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model); | ||||
|     mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, | ||||
|                            machine->cpu_model); | ||||
|  | ||||
|     /* External Flash (EMIFS) */ | ||||
|     memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size); | ||||
| @@ -189,29 +190,29 @@ static void sx1_init(QEMUMachineInitArgs *args, const int version) | ||||
|                                 OMAP_CS1_BASE, &cs[1]); | ||||
|     } | ||||
|  | ||||
|     if (!args->kernel_filename && !fl_idx && !qtest_enabled()) { | ||||
|     if (!machine->kernel_filename && !fl_idx && !qtest_enabled()) { | ||||
|         fprintf(stderr, "Kernel or Flash image must be specified\n"); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     /* Load the kernel.  */ | ||||
|     sx1_binfo.kernel_filename = args->kernel_filename; | ||||
|     sx1_binfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     sx1_binfo.initrd_filename = args->initrd_filename; | ||||
|     sx1_binfo.kernel_filename = machine->kernel_filename; | ||||
|     sx1_binfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     sx1_binfo.initrd_filename = machine->initrd_filename; | ||||
|     arm_load_kernel(mpu->cpu, &sx1_binfo); | ||||
|  | ||||
|     /* TODO: fix next line */ | ||||
|     //~ qemu_console_resize(ds, 640, 480); | ||||
| } | ||||
|  | ||||
| static void sx1_init_v1(QEMUMachineInitArgs *args) | ||||
| static void sx1_init_v1(MachineState *machine) | ||||
| { | ||||
|     sx1_init(args, 1); | ||||
|     sx1_init(machine, 1); | ||||
| } | ||||
|  | ||||
| static void sx1_init_v2(QEMUMachineInitArgs *args) | ||||
| static void sx1_init_v2(MachineState *machine) | ||||
| { | ||||
|     sx1_init(args, 2); | ||||
|     sx1_init(machine, 2); | ||||
| } | ||||
|  | ||||
| static QEMUMachine sx1_machine_v2 = { | ||||
|   | ||||
| @@ -191,12 +191,12 @@ static struct arm_boot_info palmte_binfo = { | ||||
|     .board_id = 0x331, | ||||
| }; | ||||
|  | ||||
| static void palmte_init(QEMUMachineInitArgs *args) | ||||
| static void palmte_init(MachineState *machine) | ||||
| { | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     MemoryRegion *address_space_mem = get_system_memory(); | ||||
|     struct omap_mpu_state_s *mpu; | ||||
|     int flash_size = 0x00800000; | ||||
|   | ||||
| @@ -45,7 +45,7 @@ static const int realview_board_id[] = { | ||||
|     0x76d | ||||
| }; | ||||
|  | ||||
| static void realview_init(QEMUMachineInitArgs *args, | ||||
| static void realview_init(MachineState *machine, | ||||
|                           enum realview_board_type board_type) | ||||
| { | ||||
|     ARMCPU *cpu = NULL; | ||||
| @@ -71,7 +71,7 @@ static void realview_init(QEMUMachineInitArgs *args, | ||||
|     uint32_t proc_id = 0; | ||||
|     uint32_t sys_id; | ||||
|     ram_addr_t low_ram_size; | ||||
|     ram_addr_t ram_size = args->ram_size; | ||||
|     ram_addr_t ram_size = machine->ram_size; | ||||
|     hwaddr periphbase = 0; | ||||
|  | ||||
|     switch (board_type) { | ||||
| @@ -91,7 +91,7 @@ static void realview_init(QEMUMachineInitArgs *args, | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, args->cpu_model); | ||||
|     cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model); | ||||
|     if (!cpu_oc) { | ||||
|         fprintf(stderr, "Unable to find CPU definition\n"); | ||||
|         exit(1); | ||||
| @@ -342,45 +342,45 @@ static void realview_init(QEMUMachineInitArgs *args, | ||||
|     memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); | ||||
|  | ||||
|     realview_binfo.ram_size = ram_size; | ||||
|     realview_binfo.kernel_filename = args->kernel_filename; | ||||
|     realview_binfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     realview_binfo.initrd_filename = args->initrd_filename; | ||||
|     realview_binfo.kernel_filename = machine->kernel_filename; | ||||
|     realview_binfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     realview_binfo.initrd_filename = machine->initrd_filename; | ||||
|     realview_binfo.nb_cpus = smp_cpus; | ||||
|     realview_binfo.board_id = realview_board_id[board_type]; | ||||
|     realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); | ||||
|     arm_load_kernel(ARM_CPU(first_cpu), &realview_binfo); | ||||
| } | ||||
|  | ||||
| static void realview_eb_init(QEMUMachineInitArgs *args) | ||||
| static void realview_eb_init(MachineState *machine) | ||||
| { | ||||
|     if (!args->cpu_model) { | ||||
|         args->cpu_model = "arm926"; | ||||
|     if (!machine->cpu_model) { | ||||
|         machine->cpu_model = "arm926"; | ||||
|     } | ||||
|     realview_init(args, BOARD_EB); | ||||
|     realview_init(machine, BOARD_EB); | ||||
| } | ||||
|  | ||||
| static void realview_eb_mpcore_init(QEMUMachineInitArgs *args) | ||||
| static void realview_eb_mpcore_init(MachineState *machine) | ||||
| { | ||||
|     if (!args->cpu_model) { | ||||
|         args->cpu_model = "arm11mpcore"; | ||||
|     if (!machine->cpu_model) { | ||||
|         machine->cpu_model = "arm11mpcore"; | ||||
|     } | ||||
|     realview_init(args, BOARD_EB_MPCORE); | ||||
|     realview_init(machine, BOARD_EB_MPCORE); | ||||
| } | ||||
|  | ||||
| static void realview_pb_a8_init(QEMUMachineInitArgs *args) | ||||
| static void realview_pb_a8_init(MachineState *machine) | ||||
| { | ||||
|     if (!args->cpu_model) { | ||||
|         args->cpu_model = "cortex-a8"; | ||||
|     if (!machine->cpu_model) { | ||||
|         machine->cpu_model = "cortex-a8"; | ||||
|     } | ||||
|     realview_init(args, BOARD_PB_A8); | ||||
|     realview_init(machine, BOARD_PB_A8); | ||||
| } | ||||
|  | ||||
| static void realview_pbx_a9_init(QEMUMachineInitArgs *args) | ||||
| static void realview_pbx_a9_init(MachineState *machine) | ||||
| { | ||||
|     if (!args->cpu_model) { | ||||
|         args->cpu_model = "cortex-a9"; | ||||
|     if (!machine->cpu_model) { | ||||
|         machine->cpu_model = "cortex-a9"; | ||||
|     } | ||||
|     realview_init(args, BOARD_PBX_A9); | ||||
|     realview_init(machine, BOARD_PBX_A9); | ||||
| } | ||||
|  | ||||
| static QEMUMachine realview_eb_machine = { | ||||
|   | ||||
| @@ -887,14 +887,14 @@ static struct arm_boot_info spitz_binfo = { | ||||
|     .ram_size = 0x04000000, | ||||
| }; | ||||
|  | ||||
| static void spitz_common_init(QEMUMachineInitArgs *args, | ||||
| static void spitz_common_init(MachineState *machine, | ||||
|                               enum spitz_model_e model, int arm_id) | ||||
| { | ||||
|     PXA2xxState *mpu; | ||||
|     DeviceState *scp0, *scp1 = NULL; | ||||
|     MemoryRegion *address_space_mem = get_system_memory(); | ||||
|     MemoryRegion *rom = g_new(MemoryRegion, 1); | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|  | ||||
|     if (!cpu_model) | ||||
|         cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; | ||||
| @@ -935,32 +935,32 @@ static void spitz_common_init(QEMUMachineInitArgs *args, | ||||
|         /* A 4.0 GB microdrive is permanently sitting in CF slot 0.  */ | ||||
|         spitz_microdrive_attach(mpu, 0); | ||||
|  | ||||
|     spitz_binfo.kernel_filename = args->kernel_filename; | ||||
|     spitz_binfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     spitz_binfo.initrd_filename = args->initrd_filename; | ||||
|     spitz_binfo.kernel_filename = machine->kernel_filename; | ||||
|     spitz_binfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     spitz_binfo.initrd_filename = machine->initrd_filename; | ||||
|     spitz_binfo.board_id = arm_id; | ||||
|     arm_load_kernel(mpu->cpu, &spitz_binfo); | ||||
|     sl_bootparam_write(SL_PXA_PARAM_BASE); | ||||
| } | ||||
|  | ||||
| static void spitz_init(QEMUMachineInitArgs *args) | ||||
| static void spitz_init(MachineState *machine) | ||||
| { | ||||
|     spitz_common_init(args, spitz, 0x2c9); | ||||
|     spitz_common_init(machine, spitz, 0x2c9); | ||||
| } | ||||
|  | ||||
| static void borzoi_init(QEMUMachineInitArgs *args) | ||||
| static void borzoi_init(MachineState *machine) | ||||
| { | ||||
|     spitz_common_init(args, borzoi, 0x33f); | ||||
|     spitz_common_init(machine, borzoi, 0x33f); | ||||
| } | ||||
|  | ||||
| static void akita_init(QEMUMachineInitArgs *args) | ||||
| static void akita_init(MachineState *machine) | ||||
| { | ||||
|     spitz_common_init(args, akita, 0x2e8); | ||||
|     spitz_common_init(machine, akita, 0x2e8); | ||||
| } | ||||
|  | ||||
| static void terrier_init(QEMUMachineInitArgs *args) | ||||
| static void terrier_init(MachineState *machine) | ||||
| { | ||||
|     spitz_common_init(args, terrier, 0x33f); | ||||
|     spitz_common_init(machine, terrier, 0x33f); | ||||
| } | ||||
|  | ||||
| static QEMUMachine akitapda_machine = { | ||||
|   | ||||
| @@ -1290,9 +1290,10 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, | ||||
|  | ||||
|             sddev = ssi_create_slave(bus, "ssi-sd"); | ||||
|             ssddev = ssi_create_slave(bus, "ssd0323"); | ||||
|             gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0), | ||||
|                                                  qdev_get_gpio_in(ssddev, 0)); | ||||
|             gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1); | ||||
|             gpio_out[GPIO_D][0] = qemu_irq_split( | ||||
|                     qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0), | ||||
|                     qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0)); | ||||
|             gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0); | ||||
|  | ||||
|             /* Make sure the select pin is high.  */ | ||||
|             qemu_irq_raise(gpio_out[GPIO_D][0]); | ||||
| @@ -1333,17 +1334,17 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, | ||||
| } | ||||
|  | ||||
| /* FIXME: Figure out how to generate these from stellaris_boards.  */ | ||||
| static void lm3s811evb_init(QEMUMachineInitArgs *args) | ||||
| static void lm3s811evb_init(MachineState *machine) | ||||
| { | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]); | ||||
| } | ||||
|  | ||||
| static void lm3s6965evb_init(QEMUMachineInitArgs *args) | ||||
| static void lm3s6965evb_init(MachineState *machine) | ||||
| { | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -211,12 +211,12 @@ static struct arm_boot_info tosa_binfo = { | ||||
|     .ram_size = 0x04000000, | ||||
| }; | ||||
|  | ||||
| static void tosa_init(QEMUMachineInitArgs *args) | ||||
| static void tosa_init(MachineState *machine) | ||||
| { | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     MemoryRegion *address_space_mem = get_system_memory(); | ||||
|     MemoryRegion *rom = g_new(MemoryRegion, 1); | ||||
|     PXA2xxState *mpu; | ||||
|   | ||||
| @@ -173,7 +173,7 @@ static int vpb_sic_init(SysBusDevice *sbd) | ||||
|  | ||||
| static struct arm_boot_info versatile_binfo; | ||||
|  | ||||
| static void versatile_init(QEMUMachineInitArgs *args, int board_id) | ||||
| static void versatile_init(MachineState *machine, int board_id) | ||||
| { | ||||
|     ARMCPU *cpu; | ||||
|     MemoryRegion *sysmem = get_system_memory(); | ||||
| @@ -190,15 +190,15 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) | ||||
|     int done_smc = 0; | ||||
|     DriveInfo *dinfo; | ||||
|  | ||||
|     if (!args->cpu_model) { | ||||
|         args->cpu_model = "arm926"; | ||||
|     if (!machine->cpu_model) { | ||||
|         machine->cpu_model = "arm926"; | ||||
|     } | ||||
|     cpu = cpu_arm_init(args->cpu_model); | ||||
|     cpu = cpu_arm_init(machine->cpu_model); | ||||
|     if (!cpu) { | ||||
|         fprintf(stderr, "Unable to find CPU definition\n"); | ||||
|         exit(1); | ||||
|     } | ||||
|     memory_region_init_ram(ram, NULL, "versatile.ram", args->ram_size); | ||||
|     memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size); | ||||
|     vmstate_register_ram_global(ram); | ||||
|     /* ??? RAM should repeat to fill physical memory space.  */ | ||||
|     /* SDRAM at address zero.  */ | ||||
| @@ -344,22 +344,22 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) | ||||
|         fprintf(stderr, "qemu: Error registering flash memory.\n"); | ||||
|     } | ||||
|  | ||||
|     versatile_binfo.ram_size = args->ram_size; | ||||
|     versatile_binfo.kernel_filename = args->kernel_filename; | ||||
|     versatile_binfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     versatile_binfo.initrd_filename = args->initrd_filename; | ||||
|     versatile_binfo.ram_size = machine->ram_size; | ||||
|     versatile_binfo.kernel_filename = machine->kernel_filename; | ||||
|     versatile_binfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     versatile_binfo.initrd_filename = machine->initrd_filename; | ||||
|     versatile_binfo.board_id = board_id; | ||||
|     arm_load_kernel(cpu, &versatile_binfo); | ||||
| } | ||||
|  | ||||
| static void vpb_init(QEMUMachineInitArgs *args) | ||||
| static void vpb_init(MachineState *machine) | ||||
| { | ||||
|     versatile_init(args, 0x183); | ||||
|     versatile_init(machine, 0x183); | ||||
| } | ||||
|  | ||||
| static void vab_init(QEMUMachineInitArgs *args) | ||||
| static void vab_init(MachineState *machine) | ||||
| { | ||||
|     versatile_init(args, 0x25e); | ||||
|     versatile_init(machine, 0x25e); | ||||
| } | ||||
|  | ||||
| static QEMUMachine versatilepb_machine = { | ||||
|   | ||||
| @@ -28,6 +28,7 @@ | ||||
| #include "net/net.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "hw/boards.h" | ||||
| #include "hw/loader.h" | ||||
| #include "exec/address-spaces.h" | ||||
| #include "sysemu/blockdev.h" | ||||
| #include "hw/block/flash.h" | ||||
| @@ -509,7 +510,7 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name, | ||||
| } | ||||
|  | ||||
| static void vexpress_common_init(VEDBoardInfo *daughterboard, | ||||
|                                  QEMUMachineInitArgs *args) | ||||
|                                  MachineState *machine) | ||||
| { | ||||
|     DeviceState *dev, *sysctl, *pl041; | ||||
|     qemu_irq pic[64]; | ||||
| @@ -525,7 +526,20 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard, | ||||
|     const hwaddr *map = daughterboard->motherboard_map; | ||||
|     int i; | ||||
|  | ||||
|     daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic); | ||||
|     daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model, | ||||
|                         pic); | ||||
|  | ||||
|     /* | ||||
|      * If a bios file was provided, attempt to map it into memory | ||||
|      */ | ||||
|     if (bios_name) { | ||||
|         const char *fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); | ||||
|         if (!fn || load_image_targphys(fn, map[VE_NORFLASH0], | ||||
|                                        VEXPRESS_FLASH_SIZE) < 0) { | ||||
|             error_report("Could not load ROM image '%s'", bios_name); | ||||
|             exit(1); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Motherboard peripherals: the wiring is the same but the | ||||
|      * addresses vary between the legacy and A-Series memory maps. | ||||
| @@ -639,10 +653,10 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard, | ||||
|                              pic[40 + i]); | ||||
|     } | ||||
|  | ||||
|     daughterboard->bootinfo.ram_size = args->ram_size; | ||||
|     daughterboard->bootinfo.kernel_filename = args->kernel_filename; | ||||
|     daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     daughterboard->bootinfo.initrd_filename = args->initrd_filename; | ||||
|     daughterboard->bootinfo.ram_size = machine->ram_size; | ||||
|     daughterboard->bootinfo.kernel_filename = machine->kernel_filename; | ||||
|     daughterboard->bootinfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     daughterboard->bootinfo.initrd_filename = machine->initrd_filename; | ||||
|     daughterboard->bootinfo.nb_cpus = smp_cpus; | ||||
|     daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID; | ||||
|     daughterboard->bootinfo.loader_start = daughterboard->loader_start; | ||||
| @@ -653,14 +667,14 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard, | ||||
|     arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo); | ||||
| } | ||||
|  | ||||
| static void vexpress_a9_init(QEMUMachineInitArgs *args) | ||||
| static void vexpress_a9_init(MachineState *machine) | ||||
| { | ||||
|     vexpress_common_init(&a9_daughterboard, args); | ||||
|     vexpress_common_init(&a9_daughterboard, machine); | ||||
| } | ||||
|  | ||||
| static void vexpress_a15_init(QEMUMachineInitArgs *args) | ||||
| static void vexpress_a15_init(MachineState *machine) | ||||
| { | ||||
|     vexpress_common_init(&a15_daughterboard, args); | ||||
|     vexpress_common_init(&a15_daughterboard, machine); | ||||
| } | ||||
|  | ||||
| static QEMUMachine vexpress_a9_machine = { | ||||
|   | ||||
| @@ -383,13 +383,13 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) | ||||
|     return board->fdt; | ||||
| } | ||||
|  | ||||
| static void machvirt_init(QEMUMachineInitArgs *args) | ||||
| static void machvirt_init(MachineState *machine) | ||||
| { | ||||
|     qemu_irq pic[NUM_IRQS]; | ||||
|     MemoryRegion *sysmem = get_system_memory(); | ||||
|     int n; | ||||
|     MemoryRegion *ram = g_new(MemoryRegion, 1); | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     VirtBoardInfo *vbi; | ||||
|  | ||||
|     if (!cpu_model) { | ||||
| @@ -415,7 +415,7 @@ static void machvirt_init(QEMUMachineInitArgs *args) | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     if (args->ram_size > vbi->memmap[VIRT_MEM].size) { | ||||
|     if (machine->ram_size > vbi->memmap[VIRT_MEM].size) { | ||||
|         error_report("mach-virt: cannot model more than 30GB RAM"); | ||||
|         exit(1); | ||||
|     } | ||||
| @@ -447,7 +447,7 @@ static void machvirt_init(QEMUMachineInitArgs *args) | ||||
|     } | ||||
|     fdt_add_cpu_nodes(vbi); | ||||
|  | ||||
|     memory_region_init_ram(ram, NULL, "mach-virt.ram", args->ram_size); | ||||
|     memory_region_init_ram(ram, NULL, "mach-virt.ram", machine->ram_size); | ||||
|     vmstate_register_ram_global(ram); | ||||
|     memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram); | ||||
|  | ||||
| @@ -461,10 +461,10 @@ static void machvirt_init(QEMUMachineInitArgs *args) | ||||
|      */ | ||||
|     create_virtio_devices(vbi, pic); | ||||
|  | ||||
|     vbi->bootinfo.ram_size = args->ram_size; | ||||
|     vbi->bootinfo.kernel_filename = args->kernel_filename; | ||||
|     vbi->bootinfo.kernel_cmdline = args->kernel_cmdline; | ||||
|     vbi->bootinfo.initrd_filename = args->initrd_filename; | ||||
|     vbi->bootinfo.ram_size = machine->ram_size; | ||||
|     vbi->bootinfo.kernel_filename = machine->kernel_filename; | ||||
|     vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline; | ||||
|     vbi->bootinfo.initrd_filename = machine->initrd_filename; | ||||
|     vbi->bootinfo.nb_cpus = smp_cpus; | ||||
|     vbi->bootinfo.board_id = -1; | ||||
|     vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base; | ||||
|   | ||||
| @@ -94,20 +94,20 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, | ||||
|         for (j = 0; j < num_ss; ++j) { | ||||
|             flash_dev = ssi_create_slave(spi, "n25q128"); | ||||
|  | ||||
|             cs_line = qdev_get_gpio_in(flash_dev, 0); | ||||
|             cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); | ||||
|             sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| static void zynq_init(QEMUMachineInitArgs *args) | ||||
| static void zynq_init(MachineState *machine) | ||||
| { | ||||
|     ram_addr_t ram_size = args->ram_size; | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     ram_addr_t ram_size = machine->ram_size; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     ObjectClass *cpu_oc; | ||||
|     ARMCPU *cpu; | ||||
|     MemoryRegion *address_space_mem = get_system_memory(); | ||||
|   | ||||
							
								
								
									
										10
									
								
								hw/arm/z2.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								hw/arm/z2.c
									
									
									
									
									
								
							| @@ -300,12 +300,12 @@ static const TypeInfo aer915_info = { | ||||
|     .class_init    = aer915_class_init, | ||||
| }; | ||||
|  | ||||
| static void z2_init(QEMUMachineInitArgs *args) | ||||
| static void z2_init(MachineState *machine) | ||||
| { | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     const char *initrd_filename = args->initrd_filename; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     const char *initrd_filename = machine->initrd_filename; | ||||
|     MemoryRegion *address_space_mem = get_system_memory(); | ||||
|     uint32_t sector_len = 0x10000; | ||||
|     PXA2xxState *mpu; | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| obj-y += ioq.o virtio-blk.o | ||||
| obj-y += virtio-blk.o | ||||
|   | ||||
| @@ -1,117 +0,0 @@ | ||||
| /* | ||||
|  * Linux AIO request queue | ||||
|  * | ||||
|  * Copyright 2012 IBM, Corp. | ||||
|  * Copyright 2012 Red Hat, Inc. and/or its affiliates | ||||
|  * | ||||
|  * Authors: | ||||
|  *   Stefan Hajnoczi <stefanha@redhat.com> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||||
|  * See the COPYING file in the top-level directory. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include "ioq.h" | ||||
|  | ||||
| void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs) | ||||
| { | ||||
|     int rc; | ||||
|  | ||||
|     ioq->fd = fd; | ||||
|     ioq->max_reqs = max_reqs; | ||||
|  | ||||
|     memset(&ioq->io_ctx, 0, sizeof ioq->io_ctx); | ||||
|     rc = io_setup(max_reqs, &ioq->io_ctx); | ||||
|     if (rc != 0) { | ||||
|         fprintf(stderr, "ioq io_setup failed %d\n", rc); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     rc = event_notifier_init(&ioq->io_notifier, 0); | ||||
|     if (rc != 0) { | ||||
|         fprintf(stderr, "ioq io event notifier creation failed %d\n", rc); | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     ioq->freelist = g_malloc0(sizeof ioq->freelist[0] * max_reqs); | ||||
|     ioq->freelist_idx = 0; | ||||
|  | ||||
|     ioq->queue = g_malloc0(sizeof ioq->queue[0] * max_reqs); | ||||
|     ioq->queue_idx = 0; | ||||
| } | ||||
|  | ||||
| void ioq_cleanup(IOQueue *ioq) | ||||
| { | ||||
|     g_free(ioq->freelist); | ||||
|     g_free(ioq->queue); | ||||
|  | ||||
|     event_notifier_cleanup(&ioq->io_notifier); | ||||
|     io_destroy(ioq->io_ctx); | ||||
| } | ||||
|  | ||||
| EventNotifier *ioq_get_notifier(IOQueue *ioq) | ||||
| { | ||||
|     return &ioq->io_notifier; | ||||
| } | ||||
|  | ||||
| struct iocb *ioq_get_iocb(IOQueue *ioq) | ||||
| { | ||||
|     /* Underflow cannot happen since ioq is sized for max_reqs */ | ||||
|     assert(ioq->freelist_idx != 0); | ||||
|  | ||||
|     struct iocb *iocb = ioq->freelist[--ioq->freelist_idx]; | ||||
|     ioq->queue[ioq->queue_idx++] = iocb; | ||||
|     return iocb; | ||||
| } | ||||
|  | ||||
| void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb) | ||||
| { | ||||
|     /* Overflow cannot happen since ioq is sized for max_reqs */ | ||||
|     assert(ioq->freelist_idx != ioq->max_reqs); | ||||
|  | ||||
|     ioq->freelist[ioq->freelist_idx++] = iocb; | ||||
| } | ||||
|  | ||||
| struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov, | ||||
|                       unsigned int count, long long offset) | ||||
| { | ||||
|     struct iocb *iocb = ioq_get_iocb(ioq); | ||||
|  | ||||
|     if (read) { | ||||
|         io_prep_preadv(iocb, ioq->fd, iov, count, offset); | ||||
|     } else { | ||||
|         io_prep_pwritev(iocb, ioq->fd, iov, count, offset); | ||||
|     } | ||||
|     io_set_eventfd(iocb, event_notifier_get_fd(&ioq->io_notifier)); | ||||
|     return iocb; | ||||
| } | ||||
|  | ||||
| int ioq_submit(IOQueue *ioq) | ||||
| { | ||||
|     int rc = io_submit(ioq->io_ctx, ioq->queue_idx, ioq->queue); | ||||
|     ioq->queue_idx = 0; /* reset */ | ||||
|     return rc; | ||||
| } | ||||
|  | ||||
| int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion, | ||||
|                        void *opaque) | ||||
| { | ||||
|     struct io_event events[ioq->max_reqs]; | ||||
|     int nevents, i; | ||||
|  | ||||
|     do { | ||||
|         nevents = io_getevents(ioq->io_ctx, 0, ioq->max_reqs, events, NULL); | ||||
|     } while (nevents < 0 && errno == EINTR); | ||||
|     if (nevents < 0) { | ||||
|         return nevents; | ||||
|     } | ||||
|  | ||||
|     for (i = 0; i < nevents; i++) { | ||||
|         ssize_t ret = ((uint64_t)events[i].res2 << 32) | events[i].res; | ||||
|  | ||||
|         completion(events[i].obj, ret, opaque); | ||||
|         ioq_put_iocb(ioq, events[i].obj); | ||||
|     } | ||||
|     return nevents; | ||||
| } | ||||
| @@ -1,57 +0,0 @@ | ||||
| /* | ||||
|  * Linux AIO request queue | ||||
|  * | ||||
|  * Copyright 2012 IBM, Corp. | ||||
|  * Copyright 2012 Red Hat, Inc. and/or its affiliates | ||||
|  * | ||||
|  * Authors: | ||||
|  *   Stefan Hajnoczi <stefanha@redhat.com> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||||
|  * See the COPYING file in the top-level directory. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef IOQ_H | ||||
| #define IOQ_H | ||||
|  | ||||
| #include <libaio.h> | ||||
| #include "qemu/event_notifier.h" | ||||
|  | ||||
| typedef struct { | ||||
|     int fd;                         /* file descriptor */ | ||||
|     unsigned int max_reqs;          /* max length of freelist and queue */ | ||||
|  | ||||
|     io_context_t io_ctx;            /* Linux AIO context */ | ||||
|     EventNotifier io_notifier;      /* Linux AIO eventfd */ | ||||
|  | ||||
|     /* Requests can complete in any order so a free list is necessary to manage | ||||
|      * available iocbs. | ||||
|      */ | ||||
|     struct iocb **freelist;         /* free iocbs */ | ||||
|     unsigned int freelist_idx; | ||||
|  | ||||
|     /* Multiple requests are queued up before submitting them all in one go */ | ||||
|     struct iocb **queue;            /* queued iocbs */ | ||||
|     unsigned int queue_idx; | ||||
| } IOQueue; | ||||
|  | ||||
| void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs); | ||||
| void ioq_cleanup(IOQueue *ioq); | ||||
| EventNotifier *ioq_get_notifier(IOQueue *ioq); | ||||
| struct iocb *ioq_get_iocb(IOQueue *ioq); | ||||
| void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb); | ||||
| struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov, | ||||
|                       unsigned int count, long long offset); | ||||
| int ioq_submit(IOQueue *ioq); | ||||
|  | ||||
| static inline unsigned int ioq_num_queued(IOQueue *ioq) | ||||
| { | ||||
|     return ioq->queue_idx; | ||||
| } | ||||
|  | ||||
| typedef void IOQueueCompletion(struct iocb *iocb, ssize_t ret, void *opaque); | ||||
| int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion, | ||||
|                        void *opaque); | ||||
|  | ||||
| #endif /* IOQ_H */ | ||||
| @@ -17,7 +17,6 @@ | ||||
| #include "qemu/thread.h" | ||||
| #include "qemu/error-report.h" | ||||
| #include "hw/virtio/dataplane/vring.h" | ||||
| #include "ioq.h" | ||||
| #include "block/block.h" | ||||
| #include "hw/virtio/virtio-blk.h" | ||||
| #include "virtio-blk.h" | ||||
| @@ -25,20 +24,14 @@ | ||||
| #include "hw/virtio/virtio-bus.h" | ||||
| #include "qom/object_interfaces.h" | ||||
|  | ||||
| enum { | ||||
|     SEG_MAX = 126,                  /* maximum number of I/O segments */ | ||||
|     VRING_MAX = SEG_MAX + 2,        /* maximum number of vring descriptors */ | ||||
|     REQ_MAX = VRING_MAX,            /* maximum number of requests in the vring, | ||||
|                                      * is VRING_MAX / 2 with traditional and | ||||
|                                      * VRING_MAX with indirect descriptors */ | ||||
| }; | ||||
|  | ||||
| typedef struct { | ||||
|     struct iocb iocb;               /* Linux AIO control block */ | ||||
|     VirtIOBlockDataPlane *s; | ||||
|     QEMUIOVector *inhdr;            /* iovecs for virtio_blk_inhdr */ | ||||
|     VirtQueueElement *elem;         /* saved data from the virtqueue */ | ||||
|     struct iovec *bounce_iov;       /* used if guest buffers are unaligned */ | ||||
|     QEMUIOVector *read_qiov;        /* for read completion /w bounce buffer */ | ||||
|     QEMUIOVector qiov;              /* original request iovecs */ | ||||
|     struct iovec bounce_iov;        /* used if guest buffers are unaligned */ | ||||
|     QEMUIOVector bounce_qiov;       /* bounce buffer iovecs */ | ||||
|     bool read;                      /* read or write? */ | ||||
| } VirtIOBlockRequest; | ||||
|  | ||||
| struct VirtIOBlockDataPlane { | ||||
| @@ -47,7 +40,6 @@ struct VirtIOBlockDataPlane { | ||||
|     bool stopping; | ||||
|  | ||||
|     VirtIOBlkConf *blk; | ||||
|     int fd;                         /* image file descriptor */ | ||||
|  | ||||
|     VirtIODevice *vdev; | ||||
|     Vring vring;                    /* virtqueue vring */ | ||||
| @@ -61,15 +53,10 @@ struct VirtIOBlockDataPlane { | ||||
|     IOThread *iothread; | ||||
|     IOThread internal_iothread_obj; | ||||
|     AioContext *ctx; | ||||
|     EventNotifier io_notifier;      /* Linux AIO completion */ | ||||
|     EventNotifier host_notifier;    /* doorbell */ | ||||
|  | ||||
|     IOQueue ioqueue;                /* Linux AIO queue (should really be per | ||||
|                                        IOThread) */ | ||||
|     VirtIOBlockRequest requests[REQ_MAX]; /* pool of requests, managed by the | ||||
|                                              queue */ | ||||
|  | ||||
|     unsigned int num_reqs; | ||||
|     /* Operation blocker on BDS */ | ||||
|     Error *blocker; | ||||
| }; | ||||
|  | ||||
| /* Raise an interrupt to signal guest, if necessary */ | ||||
| @@ -82,33 +69,28 @@ static void notify_guest(VirtIOBlockDataPlane *s) | ||||
|     event_notifier_set(s->guest_notifier); | ||||
| } | ||||
|  | ||||
| static void complete_request(struct iocb *iocb, ssize_t ret, void *opaque) | ||||
| static void complete_rdwr(void *opaque, int ret) | ||||
| { | ||||
|     VirtIOBlockDataPlane *s = opaque; | ||||
|     VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); | ||||
|     VirtIOBlockRequest *req = opaque; | ||||
|     struct virtio_blk_inhdr hdr; | ||||
|     int len; | ||||
|  | ||||
|     if (likely(ret >= 0)) { | ||||
|     if (likely(ret == 0)) { | ||||
|         hdr.status = VIRTIO_BLK_S_OK; | ||||
|         len = ret; | ||||
|         len = req->qiov.size; | ||||
|     } else { | ||||
|         hdr.status = VIRTIO_BLK_S_IOERR; | ||||
|         len = 0; | ||||
|     } | ||||
|  | ||||
|     trace_virtio_blk_data_plane_complete_request(s, req->elem->index, ret); | ||||
|     trace_virtio_blk_data_plane_complete_request(req->s, req->elem->index, ret); | ||||
|  | ||||
|     if (req->read_qiov) { | ||||
|         assert(req->bounce_iov); | ||||
|         qemu_iovec_from_buf(req->read_qiov, 0, req->bounce_iov->iov_base, len); | ||||
|         qemu_iovec_destroy(req->read_qiov); | ||||
|         g_slice_free(QEMUIOVector, req->read_qiov); | ||||
|     if (req->read && req->bounce_iov.iov_base) { | ||||
|         qemu_iovec_from_buf(&req->qiov, 0, req->bounce_iov.iov_base, len); | ||||
|     } | ||||
|  | ||||
|     if (req->bounce_iov) { | ||||
|         qemu_vfree(req->bounce_iov->iov_base); | ||||
|         g_slice_free(struct iovec, req->bounce_iov); | ||||
|     if (req->bounce_iov.iov_base) { | ||||
|         qemu_vfree(req->bounce_iov.iov_base); | ||||
|     } | ||||
|  | ||||
|     qemu_iovec_from_buf(req->inhdr, 0, &hdr, sizeof(hdr)); | ||||
| @@ -119,9 +101,9 @@ static void complete_request(struct iocb *iocb, ssize_t ret, void *opaque) | ||||
|      * written to, but for virtio-blk it seems to be the number of bytes | ||||
|      * transferred plus the status bytes. | ||||
|      */ | ||||
|     vring_push(&s->vring, req->elem, len + sizeof(hdr)); | ||||
|     req->elem = NULL; | ||||
|     s->num_reqs--; | ||||
|     vring_push(&req->s->vring, req->elem, len + sizeof(hdr)); | ||||
|     notify_guest(req->s); | ||||
|     g_slice_free(VirtIOBlockRequest, req); | ||||
| } | ||||
|  | ||||
| static void complete_request_early(VirtIOBlockDataPlane *s, VirtQueueElement *elem, | ||||
| @@ -152,51 +134,87 @@ static void do_get_id_cmd(VirtIOBlockDataPlane *s, | ||||
|     complete_request_early(s, elem, inhdr, VIRTIO_BLK_S_OK); | ||||
| } | ||||
|  | ||||
| static int do_rdwr_cmd(VirtIOBlockDataPlane *s, bool read, | ||||
|                        struct iovec *iov, unsigned iov_cnt, | ||||
|                        long long offset, VirtQueueElement *elem, | ||||
|                        QEMUIOVector *inhdr) | ||||
| static void do_rdwr_cmd(VirtIOBlockDataPlane *s, bool read, | ||||
|                         struct iovec *iov, unsigned iov_cnt, | ||||
|                         int64_t sector_num, VirtQueueElement *elem, | ||||
|                         QEMUIOVector *inhdr) | ||||
| { | ||||
|     struct iocb *iocb; | ||||
|     QEMUIOVector qiov; | ||||
|     struct iovec *bounce_iov = NULL; | ||||
|     QEMUIOVector *read_qiov = NULL; | ||||
|     VirtIOBlockRequest *req = g_slice_new0(VirtIOBlockRequest); | ||||
|     QEMUIOVector *qiov; | ||||
|     int nb_sectors; | ||||
|  | ||||
|     qemu_iovec_init_external(&qiov, iov, iov_cnt); | ||||
|     if (!bdrv_qiov_is_aligned(s->blk->conf.bs, &qiov)) { | ||||
|         void *bounce_buffer = qemu_blockalign(s->blk->conf.bs, qiov.size); | ||||
|     /* Fill in virtio block metadata needed for completion */ | ||||
|     req->s = s; | ||||
|     req->elem = elem; | ||||
|     req->inhdr = inhdr; | ||||
|     req->read = read; | ||||
|     qemu_iovec_init_external(&req->qiov, iov, iov_cnt); | ||||
|  | ||||
|         if (read) { | ||||
|             /* Need to copy back from bounce buffer on completion */ | ||||
|             read_qiov = g_slice_new(QEMUIOVector); | ||||
|             qemu_iovec_init(read_qiov, iov_cnt); | ||||
|             qemu_iovec_concat_iov(read_qiov, iov, iov_cnt, 0, qiov.size); | ||||
|         } else { | ||||
|             qemu_iovec_to_buf(&qiov, 0, bounce_buffer, qiov.size); | ||||
|     qiov = &req->qiov; | ||||
|  | ||||
|     if (!bdrv_qiov_is_aligned(s->blk->conf.bs, qiov)) { | ||||
|         void *bounce_buffer = qemu_blockalign(s->blk->conf.bs, qiov->size); | ||||
|  | ||||
|         /* Populate bounce buffer with data for writes */ | ||||
|         if (!read) { | ||||
|             qemu_iovec_to_buf(qiov, 0, bounce_buffer, qiov->size); | ||||
|         } | ||||
|  | ||||
|         /* Redirect I/O to aligned bounce buffer */ | ||||
|         bounce_iov = g_slice_new(struct iovec); | ||||
|         bounce_iov->iov_base = bounce_buffer; | ||||
|         bounce_iov->iov_len = qiov.size; | ||||
|         iov = bounce_iov; | ||||
|         iov_cnt = 1; | ||||
|         req->bounce_iov.iov_base = bounce_buffer; | ||||
|         req->bounce_iov.iov_len = qiov->size; | ||||
|         qemu_iovec_init_external(&req->bounce_qiov, &req->bounce_iov, 1); | ||||
|         qiov = &req->bounce_qiov; | ||||
|     } | ||||
|  | ||||
|     iocb = ioq_rdwr(&s->ioqueue, read, iov, iov_cnt, offset); | ||||
|     nb_sectors = qiov->size / BDRV_SECTOR_SIZE; | ||||
|  | ||||
|     /* Fill in virtio block metadata needed for completion */ | ||||
|     VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); | ||||
|     req->elem = elem; | ||||
|     req->inhdr = inhdr; | ||||
|     req->bounce_iov = bounce_iov; | ||||
|     req->read_qiov = read_qiov; | ||||
|     return 0; | ||||
|     if (read) { | ||||
|         bdrv_aio_readv(s->blk->conf.bs, sector_num, qiov, nb_sectors, | ||||
|                        complete_rdwr, req); | ||||
|     } else { | ||||
|         bdrv_aio_writev(s->blk->conf.bs, sector_num, qiov, nb_sectors, | ||||
|                         complete_rdwr, req); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int process_request(IOQueue *ioq, VirtQueueElement *elem) | ||||
| static void complete_flush(void *opaque, int ret) | ||||
| { | ||||
|     VirtIOBlockRequest *req = opaque; | ||||
|     unsigned char status; | ||||
|  | ||||
|     if (ret == 0) { | ||||
|         status = VIRTIO_BLK_S_OK; | ||||
|     } else { | ||||
|         status = VIRTIO_BLK_S_IOERR; | ||||
|     } | ||||
|  | ||||
|     complete_request_early(req->s, req->elem, req->inhdr, status); | ||||
|     g_slice_free(VirtIOBlockRequest, req); | ||||
| } | ||||
|  | ||||
| static void do_flush_cmd(VirtIOBlockDataPlane *s, VirtQueueElement *elem, | ||||
|                          QEMUIOVector *inhdr) | ||||
| { | ||||
|     VirtIOBlockRequest *req = g_slice_new(VirtIOBlockRequest); | ||||
|     req->s = s; | ||||
|     req->elem = elem; | ||||
|     req->inhdr = inhdr; | ||||
|  | ||||
|     bdrv_aio_flush(s->blk->conf.bs, complete_flush, req); | ||||
| } | ||||
|  | ||||
| static void do_scsi_cmd(VirtIOBlockDataPlane *s, VirtQueueElement *elem, | ||||
|                         QEMUIOVector *inhdr) | ||||
| { | ||||
|     int status; | ||||
|  | ||||
|     status = virtio_blk_handle_scsi_req(VIRTIO_BLK(s->vdev), elem); | ||||
|     complete_request_early(s, elem, inhdr, status); | ||||
| } | ||||
|  | ||||
| static int process_request(VirtIOBlockDataPlane *s, VirtQueueElement *elem) | ||||
| { | ||||
|     VirtIOBlockDataPlane *s = container_of(ioq, VirtIOBlockDataPlane, ioqueue); | ||||
|     struct iovec *iov = elem->out_sg; | ||||
|     struct iovec *in_iov = elem->in_sg; | ||||
|     unsigned out_num = elem->out_num; | ||||
| @@ -231,25 +249,23 @@ static int process_request(IOQueue *ioq, VirtQueueElement *elem) | ||||
|  | ||||
|     switch (outhdr.type) { | ||||
|     case VIRTIO_BLK_T_IN: | ||||
|         do_rdwr_cmd(s, true, in_iov, in_num, outhdr.sector * 512, elem, inhdr); | ||||
|         do_rdwr_cmd(s, true, in_iov, in_num, | ||||
|                     outhdr.sector * 512 / BDRV_SECTOR_SIZE, | ||||
|                     elem, inhdr); | ||||
|         return 0; | ||||
|  | ||||
|     case VIRTIO_BLK_T_OUT: | ||||
|         do_rdwr_cmd(s, false, iov, out_num, outhdr.sector * 512, elem, inhdr); | ||||
|         do_rdwr_cmd(s, false, iov, out_num, | ||||
|                     outhdr.sector * 512 / BDRV_SECTOR_SIZE, | ||||
|                     elem, inhdr); | ||||
|         return 0; | ||||
|  | ||||
|     case VIRTIO_BLK_T_SCSI_CMD: | ||||
|         /* TODO support SCSI commands */ | ||||
|         complete_request_early(s, elem, inhdr, VIRTIO_BLK_S_UNSUPP); | ||||
|         do_scsi_cmd(s, elem, inhdr); | ||||
|         return 0; | ||||
|  | ||||
|     case VIRTIO_BLK_T_FLUSH: | ||||
|         /* TODO fdsync not supported by Linux AIO, do it synchronously here! */ | ||||
|         if (qemu_fdatasync(s->fd) < 0) { | ||||
|             complete_request_early(s, elem, inhdr, VIRTIO_BLK_S_IOERR); | ||||
|         } else { | ||||
|             complete_request_early(s, elem, inhdr, VIRTIO_BLK_S_OK); | ||||
|         } | ||||
|         do_flush_cmd(s, elem, inhdr); | ||||
|         return 0; | ||||
|  | ||||
|     case VIRTIO_BLK_T_GET_ID: | ||||
| @@ -271,7 +287,6 @@ static void handle_notify(EventNotifier *e) | ||||
|  | ||||
|     VirtQueueElement *elem; | ||||
|     int ret; | ||||
|     unsigned int num_queued; | ||||
|  | ||||
|     event_notifier_test_and_clear(&s->host_notifier); | ||||
|     for (;;) { | ||||
| @@ -288,7 +303,7 @@ static void handle_notify(EventNotifier *e) | ||||
|             trace_virtio_blk_data_plane_process_request(s, elem->out_num, | ||||
|                                                         elem->in_num, elem->index); | ||||
|  | ||||
|             if (process_request(&s->ioqueue, elem) < 0) { | ||||
|             if (process_request(s, elem) < 0) { | ||||
|                 vring_set_broken(&s->vring); | ||||
|                 vring_free_element(elem); | ||||
|                 ret = -EFAULT; | ||||
| @@ -303,44 +318,10 @@ static void handle_notify(EventNotifier *e) | ||||
|             if (vring_enable_notification(s->vdev, &s->vring)) { | ||||
|                 break; | ||||
|             } | ||||
|         } else { /* ret == -ENOBUFS or fatal error, iovecs[] is depleted */ | ||||
|             /* Since there are no iovecs[] left, stop processing for now.  Do | ||||
|              * not re-enable guest->host notifies since the I/O completion | ||||
|              * handler knows to check for more vring descriptors anyway. | ||||
|              */ | ||||
|         } else { /* fatal error */ | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     num_queued = ioq_num_queued(&s->ioqueue); | ||||
|     if (num_queued > 0) { | ||||
|         s->num_reqs += num_queued; | ||||
|  | ||||
|         int rc = ioq_submit(&s->ioqueue); | ||||
|         if (unlikely(rc < 0)) { | ||||
|             fprintf(stderr, "ioq_submit failed %d\n", rc); | ||||
|             exit(1); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void handle_io(EventNotifier *e) | ||||
| { | ||||
|     VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, | ||||
|                                            io_notifier); | ||||
|  | ||||
|     event_notifier_test_and_clear(&s->io_notifier); | ||||
|     if (ioq_run_completion(&s->ioqueue, complete_request, s) > 0) { | ||||
|         notify_guest(s); | ||||
|     } | ||||
|  | ||||
|     /* If there were more requests than iovecs, the vring will not be empty yet | ||||
|      * so check again.  There should now be enough resources to process more | ||||
|      * requests. | ||||
|      */ | ||||
|     if (unlikely(vring_more_avail(&s->vring))) { | ||||
|         handle_notify(&s->host_notifier); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Context: QEMU global mutex held */ | ||||
| @@ -349,7 +330,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, | ||||
|                                   Error **errp) | ||||
| { | ||||
|     VirtIOBlockDataPlane *s; | ||||
|     int fd; | ||||
|     Error *local_err = NULL; | ||||
|  | ||||
|     *dataplane = NULL; | ||||
|  | ||||
| @@ -357,37 +338,18 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (blk->scsi) { | ||||
|         error_setg(errp, | ||||
|                    "device is incompatible with x-data-plane, use scsi=off"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (blk->config_wce) { | ||||
|         error_setg(errp, "device is incompatible with x-data-plane, " | ||||
|                          "use config-wce=off"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /* If dataplane is (re-)enabled while the guest is running there could be | ||||
|      * block jobs that can conflict. | ||||
|      */ | ||||
|     if (bdrv_in_use(blk->conf.bs)) { | ||||
|         error_setg(errp, | ||||
|                    "cannot start dataplane thread while device is in use"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     fd = raw_get_aio_fd(blk->conf.bs); | ||||
|     if (fd < 0) { | ||||
|         error_setg(errp, "drive is incompatible with x-data-plane, " | ||||
|                          "use format=raw,cache=none,aio=native"); | ||||
|     if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) { | ||||
|         error_report("cannot start dataplane thread: %s", | ||||
|                       error_get_pretty(local_err)); | ||||
|         error_free(local_err); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     s = g_new0(VirtIOBlockDataPlane, 1); | ||||
|     s->vdev = vdev; | ||||
|     s->fd = fd; | ||||
|     s->blk = blk; | ||||
|  | ||||
|     if (blk->iothread) { | ||||
| @@ -406,8 +368,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, | ||||
|     } | ||||
|     s->ctx = iothread_get_aio_context(s->iothread); | ||||
|  | ||||
|     /* Prevent block operations that conflict with data plane thread */ | ||||
|     bdrv_set_in_use(blk->conf.bs, 1); | ||||
|     error_setg(&s->blocker, "block device is in use by data plane"); | ||||
|     bdrv_op_block_all(blk->conf.bs, s->blocker); | ||||
|  | ||||
|     *dataplane = s; | ||||
| } | ||||
| @@ -420,7 +382,8 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) | ||||
|     } | ||||
|  | ||||
|     virtio_blk_data_plane_stop(s); | ||||
|     bdrv_set_in_use(s->blk->conf.bs, 0); | ||||
|     bdrv_op_unblock_all(s->blk->conf.bs, s->blocker); | ||||
|     error_free(s->blocker); | ||||
|     object_unref(OBJECT(s->iothread)); | ||||
|     g_free(s); | ||||
| } | ||||
| @@ -431,7 +394,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) | ||||
|     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); | ||||
|     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); | ||||
|     VirtQueue *vq; | ||||
|     int i; | ||||
|  | ||||
|     if (s->started) { | ||||
|         return; | ||||
| @@ -464,24 +426,18 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) | ||||
|     } | ||||
|     s->host_notifier = *virtio_queue_get_host_notifier(vq); | ||||
|  | ||||
|     /* Set up ioqueue */ | ||||
|     ioq_init(&s->ioqueue, s->fd, REQ_MAX); | ||||
|     for (i = 0; i < ARRAY_SIZE(s->requests); i++) { | ||||
|         ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb); | ||||
|     } | ||||
|     s->io_notifier = *ioq_get_notifier(&s->ioqueue); | ||||
|  | ||||
|     s->starting = false; | ||||
|     s->started = true; | ||||
|     trace_virtio_blk_data_plane_start(s); | ||||
|  | ||||
|     bdrv_set_aio_context(s->blk->conf.bs, s->ctx); | ||||
|  | ||||
|     /* Kick right away to begin processing requests already in vring */ | ||||
|     event_notifier_set(virtio_queue_get_host_notifier(vq)); | ||||
|  | ||||
|     /* Get this show started by hooking up our callbacks */ | ||||
|     aio_context_acquire(s->ctx); | ||||
|     aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify); | ||||
|     aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io); | ||||
|     aio_context_release(s->ctx); | ||||
| } | ||||
|  | ||||
| @@ -501,13 +457,8 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) | ||||
|     /* Stop notifications for new requests from guest */ | ||||
|     aio_set_event_notifier(s->ctx, &s->host_notifier, NULL); | ||||
|  | ||||
|     /* Complete pending requests */ | ||||
|     while (s->num_reqs > 0) { | ||||
|         aio_poll(s->ctx, true); | ||||
|     } | ||||
|  | ||||
|     /* Stop ioq callbacks (there are no pending requests left) */ | ||||
|     aio_set_event_notifier(s->ctx, &s->io_notifier, NULL); | ||||
|     /* Drain and switch bs back to the QEMU main loop */ | ||||
|     bdrv_set_aio_context(s->blk->conf.bs, qemu_get_aio_context()); | ||||
|  | ||||
|     aio_context_release(s->ctx); | ||||
|  | ||||
| @@ -516,7 +467,6 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) | ||||
|      */ | ||||
|     vring_teardown(&s->vring, s->vdev, 0); | ||||
|  | ||||
|     ioq_cleanup(&s->ioqueue); | ||||
|     k->set_host_notifier(qbus->parent, 0, false); | ||||
|  | ||||
|     /* Clean up guest notifier (irq) */ | ||||
|   | ||||
| @@ -33,7 +33,6 @@ typedef struct VirtIOBlockReq | ||||
|     VirtQueueElement elem; | ||||
|     struct virtio_blk_inhdr *in; | ||||
|     struct virtio_blk_outhdr *out; | ||||
|     struct virtio_scsi_inhdr *scsi; | ||||
|     QEMUIOVector qiov; | ||||
|     struct VirtIOBlockReq *next; | ||||
|     BlockAcctCookie acct; | ||||
| @@ -125,13 +124,15 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) | ||||
|     return req; | ||||
| } | ||||
|  | ||||
| static void virtio_blk_handle_scsi(VirtIOBlockReq *req) | ||||
| int virtio_blk_handle_scsi_req(VirtIOBlock *blk, | ||||
|                                VirtQueueElement *elem) | ||||
| { | ||||
| #ifdef __linux__ | ||||
|     int ret; | ||||
|     int i; | ||||
| #endif | ||||
|     int status = VIRTIO_BLK_S_OK; | ||||
|     struct virtio_scsi_inhdr *scsi = NULL; | ||||
| #ifdef __linux__ | ||||
|     int i; | ||||
|     struct sg_io_hdr hdr; | ||||
| #endif | ||||
|  | ||||
|     /* | ||||
|      * We require at least one output segment each for the virtio_blk_outhdr | ||||
| @@ -140,19 +141,18 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) | ||||
|      * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr | ||||
|      * and the sense buffer pointer in the input segments. | ||||
|      */ | ||||
|     if (req->elem.out_num < 2 || req->elem.in_num < 3) { | ||||
|         virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); | ||||
|         g_free(req); | ||||
|         return; | ||||
|     if (elem->out_num < 2 || elem->in_num < 3) { | ||||
|         status = VIRTIO_BLK_S_IOERR; | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * The scsi inhdr is placed in the second-to-last input segment, just | ||||
|      * before the regular inhdr. | ||||
|      */ | ||||
|     req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; | ||||
|     scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base; | ||||
|  | ||||
|     if (!req->dev->blk.scsi) { | ||||
|     if (!blk->blk.scsi) { | ||||
|         status = VIRTIO_BLK_S_UNSUPP; | ||||
|         goto fail; | ||||
|     } | ||||
| @@ -160,43 +160,42 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) | ||||
|     /* | ||||
|      * No support for bidirection commands yet. | ||||
|      */ | ||||
|     if (req->elem.out_num > 2 && req->elem.in_num > 3) { | ||||
|     if (elem->out_num > 2 && elem->in_num > 3) { | ||||
|         status = VIRTIO_BLK_S_UNSUPP; | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
| #ifdef __linux__ | ||||
|     struct sg_io_hdr hdr; | ||||
|     memset(&hdr, 0, sizeof(struct sg_io_hdr)); | ||||
|     hdr.interface_id = 'S'; | ||||
|     hdr.cmd_len = req->elem.out_sg[1].iov_len; | ||||
|     hdr.cmdp = req->elem.out_sg[1].iov_base; | ||||
|     hdr.cmd_len = elem->out_sg[1].iov_len; | ||||
|     hdr.cmdp = elem->out_sg[1].iov_base; | ||||
|     hdr.dxfer_len = 0; | ||||
|  | ||||
|     if (req->elem.out_num > 2) { | ||||
|     if (elem->out_num > 2) { | ||||
|         /* | ||||
|          * If there are more than the minimally required 2 output segments | ||||
|          * there is write payload starting from the third iovec. | ||||
|          */ | ||||
|         hdr.dxfer_direction = SG_DXFER_TO_DEV; | ||||
|         hdr.iovec_count = req->elem.out_num - 2; | ||||
|         hdr.iovec_count = elem->out_num - 2; | ||||
|  | ||||
|         for (i = 0; i < hdr.iovec_count; i++) | ||||
|             hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len; | ||||
|             hdr.dxfer_len += elem->out_sg[i + 2].iov_len; | ||||
|  | ||||
|         hdr.dxferp = req->elem.out_sg + 2; | ||||
|         hdr.dxferp = elem->out_sg + 2; | ||||
|  | ||||
|     } else if (req->elem.in_num > 3) { | ||||
|     } else if (elem->in_num > 3) { | ||||
|         /* | ||||
|          * If we have more than 3 input segments the guest wants to actually | ||||
|          * read data. | ||||
|          */ | ||||
|         hdr.dxfer_direction = SG_DXFER_FROM_DEV; | ||||
|         hdr.iovec_count = req->elem.in_num - 3; | ||||
|         hdr.iovec_count = elem->in_num - 3; | ||||
|         for (i = 0; i < hdr.iovec_count; i++) | ||||
|             hdr.dxfer_len += req->elem.in_sg[i].iov_len; | ||||
|             hdr.dxfer_len += elem->in_sg[i].iov_len; | ||||
|  | ||||
|         hdr.dxferp = req->elem.in_sg; | ||||
|         hdr.dxferp = elem->in_sg; | ||||
|     } else { | ||||
|         /* | ||||
|          * Some SCSI commands don't actually transfer any data. | ||||
| @@ -204,11 +203,11 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) | ||||
|         hdr.dxfer_direction = SG_DXFER_NONE; | ||||
|     } | ||||
|  | ||||
|     hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base; | ||||
|     hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len; | ||||
|     hdr.sbp = elem->in_sg[elem->in_num - 3].iov_base; | ||||
|     hdr.mx_sb_len = elem->in_sg[elem->in_num - 3].iov_len; | ||||
|  | ||||
|     ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr); | ||||
|     if (ret) { | ||||
|     status = bdrv_ioctl(blk->bs, SG_IO, &hdr); | ||||
|     if (status) { | ||||
|         status = VIRTIO_BLK_S_UNSUPP; | ||||
|         goto fail; | ||||
|     } | ||||
| @@ -224,23 +223,31 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) | ||||
|         hdr.status = CHECK_CONDITION; | ||||
|     } | ||||
|  | ||||
|     stl_p(&req->scsi->errors, | ||||
|     stl_p(&scsi->errors, | ||||
|           hdr.status | (hdr.msg_status << 8) | | ||||
|           (hdr.host_status << 16) | (hdr.driver_status << 24)); | ||||
|     stl_p(&req->scsi->residual, hdr.resid); | ||||
|     stl_p(&req->scsi->sense_len, hdr.sb_len_wr); | ||||
|     stl_p(&req->scsi->data_len, hdr.dxfer_len); | ||||
|     stl_p(&scsi->residual, hdr.resid); | ||||
|     stl_p(&scsi->sense_len, hdr.sb_len_wr); | ||||
|     stl_p(&scsi->data_len, hdr.dxfer_len); | ||||
|  | ||||
|     virtio_blk_req_complete(req, status); | ||||
|     g_free(req); | ||||
|     return; | ||||
|     return status; | ||||
| #else | ||||
|     abort(); | ||||
| #endif | ||||
|  | ||||
| fail: | ||||
|     /* Just put anything nonzero so that the ioctl fails in the guest.  */ | ||||
|     stl_p(&req->scsi->errors, 255); | ||||
|     if (scsi) { | ||||
|         stl_p(&scsi->errors, 255); | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| static void virtio_blk_handle_scsi(VirtIOBlockReq *req) | ||||
| { | ||||
|     int status; | ||||
|  | ||||
|     status = virtio_blk_handle_scsi_req(req->dev, &req->elem); | ||||
|     virtio_blk_req_complete(req, status); | ||||
|     g_free(req); | ||||
| } | ||||
| @@ -487,12 +494,12 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) | ||||
|  | ||||
|     bdrv_get_geometry(s->bs, &capacity); | ||||
|     memset(&blkcfg, 0, sizeof(blkcfg)); | ||||
|     stq_raw(&blkcfg.capacity, capacity); | ||||
|     stl_raw(&blkcfg.seg_max, 128 - 2); | ||||
|     stw_raw(&blkcfg.cylinders, s->conf->cyls); | ||||
|     stl_raw(&blkcfg.blk_size, blk_size); | ||||
|     stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size); | ||||
|     stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size); | ||||
|     stq_p(&blkcfg.capacity, capacity); | ||||
|     stl_p(&blkcfg.seg_max, 128 - 2); | ||||
|     stw_p(&blkcfg.cylinders, s->conf->cyls); | ||||
|     stl_p(&blkcfg.blk_size, blk_size); | ||||
|     stw_p(&blkcfg.min_io_size, s->conf->min_io_size / blk_size); | ||||
|     stw_p(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size); | ||||
|     blkcfg.heads = s->conf->heads; | ||||
|     /* | ||||
|      * We must ensure that the block device capacity is a multiple of | ||||
| @@ -523,7 +530,10 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) | ||||
|     struct virtio_blk_config blkcfg; | ||||
|  | ||||
|     memcpy(&blkcfg, config, sizeof(blkcfg)); | ||||
|  | ||||
|     aio_context_acquire(bdrv_get_aio_context(s->bs)); | ||||
|     bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0); | ||||
|     aio_context_release(bdrv_get_aio_context(s->bs)); | ||||
| } | ||||
|  | ||||
| static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) | ||||
| @@ -582,7 +592,10 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) | ||||
|      * s->bs would erroneously be placed in writethrough mode. | ||||
|      */ | ||||
|     if (!(features & (1 << VIRTIO_BLK_F_CONFIG_WCE))) { | ||||
|         bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE))); | ||||
|         aio_context_acquire(bdrv_get_aio_context(s->bs)); | ||||
|         bdrv_set_enable_write_cache(s->bs, | ||||
|                                     !!(features & (1 << VIRTIO_BLK_F_WCE))); | ||||
|         aio_context_release(bdrv_get_aio_context(s->bs)); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -34,6 +34,7 @@ | ||||
| typedef struct PCISerialState { | ||||
|     PCIDevice dev; | ||||
|     SerialState state; | ||||
|     uint8_t prog_if; | ||||
| } PCISerialState; | ||||
|  | ||||
| typedef struct PCIMultiSerialState { | ||||
| @@ -44,6 +45,7 @@ typedef struct PCIMultiSerialState { | ||||
|     SerialState  state[PCI_SERIAL_MAX_PORTS]; | ||||
|     uint32_t     level[PCI_SERIAL_MAX_PORTS]; | ||||
|     qemu_irq     *irqs; | ||||
|     uint8_t      prog_if; | ||||
| } PCIMultiSerialState; | ||||
|  | ||||
| static int serial_pci_init(PCIDevice *dev) | ||||
| @@ -60,6 +62,7 @@ static int serial_pci_init(PCIDevice *dev) | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; | ||||
|     pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; | ||||
|     s->irq = pci_allocate_irq(&pci->dev); | ||||
|  | ||||
| @@ -101,6 +104,7 @@ static int multi_serial_pci_init(PCIDevice *dev) | ||||
|     assert(pci->ports > 0); | ||||
|     assert(pci->ports <= PCI_SERIAL_MAX_PORTS); | ||||
|  | ||||
|     pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; | ||||
|     pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; | ||||
|     memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * pci->ports); | ||||
|     pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); | ||||
| @@ -177,12 +181,14 @@ static const VMStateDescription vmstate_pci_multi_serial = { | ||||
|  | ||||
| static Property serial_pci_properties[] = { | ||||
|     DEFINE_PROP_CHR("chardev",  PCISerialState, state.chr), | ||||
|     DEFINE_PROP_UINT8("prog_if",  PCISerialState, prog_if, 0x02), | ||||
|     DEFINE_PROP_END_OF_LIST(), | ||||
| }; | ||||
|  | ||||
| static Property multi_2x_serial_pci_properties[] = { | ||||
|     DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr), | ||||
|     DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr), | ||||
|     DEFINE_PROP_UINT8("prog_if",  PCIMultiSerialState, prog_if, 0x02), | ||||
|     DEFINE_PROP_END_OF_LIST(), | ||||
| }; | ||||
|  | ||||
| @@ -191,6 +197,7 @@ static Property multi_4x_serial_pci_properties[] = { | ||||
|     DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr), | ||||
|     DEFINE_PROP_CHR("chardev3",  PCIMultiSerialState, state[2].chr), | ||||
|     DEFINE_PROP_CHR("chardev4",  PCIMultiSerialState, state[3].chr), | ||||
|     DEFINE_PROP_UINT8("prog_if",  PCIMultiSerialState, prog_if, 0x02), | ||||
|     DEFINE_PROP_END_OF_LIST(), | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -87,6 +87,11 @@ static void uart_update_status(XilinxUARTLite *s) | ||||
|     s->regs[R_STATUS] = r; | ||||
| } | ||||
|  | ||||
| static void xilinx_uartlite_reset(DeviceState *dev) | ||||
| { | ||||
|     uart_update_status(XILINX_UARTLITE(dev)); | ||||
| } | ||||
|  | ||||
| static uint64_t | ||||
| uart_read(void *opaque, hwaddr addr, unsigned int size) | ||||
| { | ||||
| @@ -196,34 +201,39 @@ static void uart_event(void *opaque, int event) | ||||
|  | ||||
| } | ||||
|  | ||||
| static int xilinx_uartlite_init(SysBusDevice *dev) | ||||
| static void xilinx_uartlite_realize(DeviceState *dev, Error **errp) | ||||
| { | ||||
|     XilinxUARTLite *s = XILINX_UARTLITE(dev); | ||||
|  | ||||
|     sysbus_init_irq(dev, &s->irq); | ||||
|  | ||||
|     uart_update_status(s); | ||||
|     memory_region_init_io(&s->mmio, OBJECT(s), &uart_ops, s, | ||||
|                           "xlnx.xps-uartlite", R_MAX * 4); | ||||
|     sysbus_init_mmio(dev, &s->mmio); | ||||
|  | ||||
|     s->chr = qemu_char_get_next_serial(); | ||||
|     if (s->chr) | ||||
|         qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void xilinx_uartlite_init(Object *obj) | ||||
| { | ||||
|     XilinxUARTLite *s = XILINX_UARTLITE(obj); | ||||
|  | ||||
|     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); | ||||
|  | ||||
|     memory_region_init_io(&s->mmio, obj, &uart_ops, s, | ||||
|                           "xlnx.xps-uartlite", R_MAX * 4); | ||||
|     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); | ||||
| } | ||||
|  | ||||
| static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) | ||||
| { | ||||
|     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); | ||||
|     DeviceClass *dc = DEVICE_CLASS(klass); | ||||
|  | ||||
|     sdc->init = xilinx_uartlite_init; | ||||
|     dc->reset = xilinx_uartlite_reset; | ||||
|     dc->realize = xilinx_uartlite_realize; | ||||
| } | ||||
|  | ||||
| static const TypeInfo xilinx_uartlite_info = { | ||||
|     .name          = TYPE_XILINX_UARTLITE, | ||||
|     .parent        = TYPE_SYS_BUS_DEVICE, | ||||
|     .instance_size = sizeof(XilinxUARTLite), | ||||
|     .instance_init = xilinx_uartlite_init, | ||||
|     .class_init    = xilinx_uartlite_class_init, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -11,6 +11,284 @@ | ||||
|  */ | ||||
|  | ||||
| #include "hw/boards.h" | ||||
| #include "qapi/visitor.h" | ||||
|  | ||||
| static char *machine_get_accel(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return g_strdup(ms->accel); | ||||
| } | ||||
|  | ||||
| static void machine_set_accel(Object *obj, const char *value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->accel = g_strdup(value); | ||||
| } | ||||
|  | ||||
| static bool machine_get_kernel_irqchip(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return ms->kernel_irqchip; | ||||
| } | ||||
|  | ||||
| static void machine_set_kernel_irqchip(Object *obj, bool value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->kernel_irqchip = value; | ||||
| } | ||||
|  | ||||
| static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v, | ||||
|                                        void *opaque, const char *name, | ||||
|                                        Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|     int64_t value = ms->kvm_shadow_mem; | ||||
|  | ||||
|     visit_type_int(v, &value, name, errp); | ||||
| } | ||||
|  | ||||
| static void machine_set_kvm_shadow_mem(Object *obj, Visitor *v, | ||||
|                                        void *opaque, const char *name, | ||||
|                                        Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|     Error *error = NULL; | ||||
|     int64_t value; | ||||
|  | ||||
|     visit_type_int(v, &value, name, &error); | ||||
|     if (error) { | ||||
|         error_propagate(errp, error); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     ms->kvm_shadow_mem = value; | ||||
| } | ||||
|  | ||||
| static char *machine_get_kernel(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return g_strdup(ms->kernel_filename); | ||||
| } | ||||
|  | ||||
| static void machine_set_kernel(Object *obj, const char *value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->kernel_filename = g_strdup(value); | ||||
| } | ||||
|  | ||||
| static char *machine_get_initrd(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return g_strdup(ms->initrd_filename); | ||||
| } | ||||
|  | ||||
| static void machine_set_initrd(Object *obj, const char *value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->initrd_filename = g_strdup(value); | ||||
| } | ||||
|  | ||||
| static char *machine_get_append(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return g_strdup(ms->kernel_cmdline); | ||||
| } | ||||
|  | ||||
| static void machine_set_append(Object *obj, const char *value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->kernel_cmdline = g_strdup(value); | ||||
| } | ||||
|  | ||||
| static char *machine_get_dtb(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return g_strdup(ms->dtb); | ||||
| } | ||||
|  | ||||
| static void machine_set_dtb(Object *obj, const char *value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->dtb = g_strdup(value); | ||||
| } | ||||
|  | ||||
| static char *machine_get_dumpdtb(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return g_strdup(ms->dumpdtb); | ||||
| } | ||||
|  | ||||
| static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->dumpdtb = g_strdup(value); | ||||
| } | ||||
|  | ||||
| static void machine_get_phandle_start(Object *obj, Visitor *v, | ||||
|                                        void *opaque, const char *name, | ||||
|                                        Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|     int64_t value = ms->phandle_start; | ||||
|  | ||||
|     visit_type_int(v, &value, name, errp); | ||||
| } | ||||
|  | ||||
| static void machine_set_phandle_start(Object *obj, Visitor *v, | ||||
|                                        void *opaque, const char *name, | ||||
|                                        Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|     Error *error = NULL; | ||||
|     int64_t value; | ||||
|  | ||||
|     visit_type_int(v, &value, name, &error); | ||||
|     if (error) { | ||||
|         error_propagate(errp, error); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     ms->phandle_start = value; | ||||
| } | ||||
|  | ||||
| static char *machine_get_dt_compatible(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return g_strdup(ms->dt_compatible); | ||||
| } | ||||
|  | ||||
| static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->dt_compatible = g_strdup(value); | ||||
| } | ||||
|  | ||||
| static bool machine_get_dump_guest_core(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return ms->dump_guest_core; | ||||
| } | ||||
|  | ||||
| static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->dump_guest_core = value; | ||||
| } | ||||
|  | ||||
| static bool machine_get_mem_merge(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return ms->mem_merge; | ||||
| } | ||||
|  | ||||
| static void machine_set_mem_merge(Object *obj, bool value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->mem_merge = value; | ||||
| } | ||||
|  | ||||
| static bool machine_get_usb(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return ms->usb; | ||||
| } | ||||
|  | ||||
| static void machine_set_usb(Object *obj, bool value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->usb = value; | ||||
| } | ||||
|  | ||||
| static char *machine_get_firmware(Object *obj, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     return g_strdup(ms->firmware); | ||||
| } | ||||
|  | ||||
| static void machine_set_firmware(Object *obj, const char *value, Error **errp) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     ms->firmware = g_strdup(value); | ||||
| } | ||||
|  | ||||
| static void machine_initfn(Object *obj) | ||||
| { | ||||
|     object_property_add_str(obj, "accel", | ||||
|                             machine_get_accel, machine_set_accel, NULL); | ||||
|     object_property_add_bool(obj, "kernel_irqchip", | ||||
|                              machine_get_kernel_irqchip, | ||||
|                              machine_set_kernel_irqchip, | ||||
|                              NULL); | ||||
|     object_property_add(obj, "kvm_shadow_mem", "int", | ||||
|                         machine_get_kvm_shadow_mem, | ||||
|                         machine_set_kvm_shadow_mem, | ||||
|                         NULL, NULL, NULL); | ||||
|     object_property_add_str(obj, "kernel", | ||||
|                             machine_get_kernel, machine_set_kernel, NULL); | ||||
|     object_property_add_str(obj, "initrd", | ||||
|                             machine_get_initrd, machine_set_initrd, NULL); | ||||
|     object_property_add_str(obj, "append", | ||||
|                             machine_get_append, machine_set_append, NULL); | ||||
|     object_property_add_str(obj, "dtb", | ||||
|                             machine_get_dtb, machine_set_dtb, NULL); | ||||
|     object_property_add_str(obj, "dumpdtb", | ||||
|                             machine_get_dumpdtb, machine_set_dumpdtb, NULL); | ||||
|     object_property_add(obj, "phandle_start", "int", | ||||
|                         machine_get_phandle_start, | ||||
|                         machine_set_phandle_start, | ||||
|                         NULL, NULL, NULL); | ||||
|     object_property_add_str(obj, "dt_compatible", | ||||
|                             machine_get_dt_compatible, | ||||
|                             machine_set_dt_compatible, | ||||
|                             NULL); | ||||
|     object_property_add_bool(obj, "dump-guest-core", | ||||
|                              machine_get_dump_guest_core, | ||||
|                              machine_set_dump_guest_core, | ||||
|                              NULL); | ||||
|     object_property_add_bool(obj, "mem-merge", | ||||
|                              machine_get_mem_merge, machine_set_mem_merge, NULL); | ||||
|     object_property_add_bool(obj, "usb", machine_get_usb, machine_set_usb, NULL); | ||||
|     object_property_add_str(obj, "firmware", | ||||
|                             machine_get_firmware, machine_set_firmware, NULL); | ||||
| } | ||||
|  | ||||
| static void machine_finalize(Object *obj) | ||||
| { | ||||
|     MachineState *ms = MACHINE(obj); | ||||
|  | ||||
|     g_free(ms->accel); | ||||
|     g_free(ms->kernel_filename); | ||||
|     g_free(ms->initrd_filename); | ||||
|     g_free(ms->kernel_cmdline); | ||||
|     g_free(ms->dtb); | ||||
|     g_free(ms->dumpdtb); | ||||
|     g_free(ms->dt_compatible); | ||||
|     g_free(ms->firmware); | ||||
| } | ||||
|  | ||||
| static const TypeInfo machine_info = { | ||||
|     .name = TYPE_MACHINE, | ||||
| @@ -18,6 +296,8 @@ static const TypeInfo machine_info = { | ||||
|     .abstract = true, | ||||
|     .class_size = sizeof(MachineClass), | ||||
|     .instance_size = sizeof(MachineState), | ||||
|     .instance_init = machine_initfn, | ||||
|     .instance_finalize = machine_finalize, | ||||
| }; | ||||
|  | ||||
| static void machine_register_types(void) | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
| #include "hw/hw.h" | ||||
| #include "hw/boards.h" | ||||
|  | ||||
| static void machine_none_init(QEMUMachineInitArgs *args) | ||||
| static void machine_none_init(MachineState *machine) | ||||
| { | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -439,11 +439,27 @@ PropertyInfo qdev_prop_iothread = { | ||||
| static int qdev_add_one_global(QemuOpts *opts, void *opaque) | ||||
| { | ||||
|     GlobalProperty *g; | ||||
|     ObjectClass *oc; | ||||
|  | ||||
|     g = g_malloc0(sizeof(*g)); | ||||
|     g->driver   = qemu_opt_get(opts, "driver"); | ||||
|     g->property = qemu_opt_get(opts, "property"); | ||||
|     g->value    = qemu_opt_get(opts, "value"); | ||||
|     oc = object_class_by_name(g->driver); | ||||
|     if (oc) { | ||||
|         DeviceClass *dc = DEVICE_CLASS(oc); | ||||
|  | ||||
|         if (dc->hotpluggable) { | ||||
|             /* If hotpluggable then skip not_used checking. */ | ||||
|             g->not_used = false; | ||||
|         } else { | ||||
|             /* Maybe a typo. */ | ||||
|             g->not_used = true; | ||||
|         } | ||||
|     } else { | ||||
|         /* Maybe a typo. */ | ||||
|         g->not_used = true; | ||||
|     } | ||||
|     qdev_prop_register_global(g); | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -955,6 +955,23 @@ void qdev_prop_register_global_list(GlobalProperty *props) | ||||
|     } | ||||
| } | ||||
|  | ||||
| int qdev_prop_check_global(void) | ||||
| { | ||||
|     GlobalProperty *prop; | ||||
|     int ret = 0; | ||||
|  | ||||
|     QTAILQ_FOREACH(prop, &global_props, next) { | ||||
|         if (!prop->not_used) { | ||||
|             continue; | ||||
|         } | ||||
|         ret = 1; | ||||
|         error_report("Warning: \"-global %s.%s=%s\" not used", | ||||
|                      prop->driver, prop->property, prop->value); | ||||
|  | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, | ||||
|                                     Error **errp) | ||||
| { | ||||
| @@ -966,6 +983,7 @@ void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, | ||||
|         if (strcmp(typename, prop->driver) != 0) { | ||||
|             continue; | ||||
|         } | ||||
|         prop->not_used = false; | ||||
|         object_property_parse(OBJECT(dev), prop->value, prop->property, &err); | ||||
|         if (err != NULL) { | ||||
|             error_propagate(errp, err); | ||||
|   | ||||
| @@ -312,30 +312,82 @@ BusState *qdev_get_parent_bus(DeviceState *dev) | ||||
|     return dev->parent_bus; | ||||
| } | ||||
|  | ||||
| static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev, | ||||
|                                                const char *name) | ||||
| { | ||||
|     NamedGPIOList *ngl; | ||||
|  | ||||
|     QLIST_FOREACH(ngl, &dev->gpios, node) { | ||||
|         /* NULL is a valid and matchable name, otherwise do a normal | ||||
|          * strcmp match. | ||||
|          */ | ||||
|         if ((!ngl->name && !name) || | ||||
|                 (name && ngl->name && strcmp(name, ngl->name) == 0)) { | ||||
|             return ngl; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     ngl = g_malloc0(sizeof(*ngl)); | ||||
|     ngl->name = g_strdup(name); | ||||
|     QLIST_INSERT_HEAD(&dev->gpios, ngl, node); | ||||
|     return ngl; | ||||
| } | ||||
|  | ||||
| void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler, | ||||
|                              const char *name, int n) | ||||
| { | ||||
|     NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); | ||||
|  | ||||
|     gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler, | ||||
|                                      dev, n); | ||||
|     gpio_list->num_in += n; | ||||
| } | ||||
|  | ||||
| void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n) | ||||
| { | ||||
|     dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler, | ||||
|                                         dev, n); | ||||
|     dev->num_gpio_in += n; | ||||
|     qdev_init_gpio_in_named(dev, handler, NULL, n); | ||||
| } | ||||
|  | ||||
| void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, | ||||
|                               const char *name, int n) | ||||
| { | ||||
|     NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); | ||||
|  | ||||
|     assert(gpio_list->num_out == 0); | ||||
|     gpio_list->num_out = n; | ||||
|     gpio_list->out = pins; | ||||
| } | ||||
|  | ||||
| void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) | ||||
| { | ||||
|     assert(dev->num_gpio_out == 0); | ||||
|     dev->num_gpio_out = n; | ||||
|     dev->gpio_out = pins; | ||||
|     qdev_init_gpio_out_named(dev, pins, NULL, n); | ||||
| } | ||||
|  | ||||
| qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n) | ||||
| { | ||||
|     NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); | ||||
|  | ||||
|     assert(n >= 0 && n < gpio_list->num_in); | ||||
|     return gpio_list->in[n]; | ||||
| } | ||||
|  | ||||
| qemu_irq qdev_get_gpio_in(DeviceState *dev, int n) | ||||
| { | ||||
|     assert(n >= 0 && n < dev->num_gpio_in); | ||||
|     return dev->gpio_in[n]; | ||||
|     return qdev_get_gpio_in_named(dev, NULL, n); | ||||
| } | ||||
|  | ||||
| void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, | ||||
|                                  qemu_irq pin) | ||||
| { | ||||
|     NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); | ||||
|  | ||||
|     assert(n >= 0 && n < gpio_list->num_out); | ||||
|     gpio_list->out[n] = pin; | ||||
| } | ||||
|  | ||||
| void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) | ||||
| { | ||||
|     assert(n >= 0 && n < dev->num_gpio_out); | ||||
|     dev->gpio_out[n] = pin; | ||||
|     qdev_connect_gpio_out_named(dev, NULL, n, pin); | ||||
| } | ||||
|  | ||||
| BusState *qdev_get_child_bus(DeviceState *dev, const char *name) | ||||
| @@ -844,6 +896,7 @@ static void device_initfn(Object *obj) | ||||
|     object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, | ||||
|                              (Object **)&dev->parent_bus, NULL, 0, | ||||
|                              &error_abort); | ||||
|     QLIST_INIT(&dev->gpios); | ||||
| } | ||||
|  | ||||
| static void device_post_init(Object *obj) | ||||
| @@ -854,10 +907,22 @@ static void device_post_init(Object *obj) | ||||
| /* Unlink device from bus and free the structure.  */ | ||||
| static void device_finalize(Object *obj) | ||||
| { | ||||
|     NamedGPIOList *ngl, *next; | ||||
|  | ||||
|     DeviceState *dev = DEVICE(obj); | ||||
|     if (dev->opts) { | ||||
|         qemu_opts_del(dev->opts); | ||||
|     } | ||||
|  | ||||
|     QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { | ||||
|         QLIST_REMOVE(ngl, node); | ||||
|         qemu_free_irqs(ngl->in); | ||||
|         g_free(ngl->name); | ||||
|         g_free(ngl); | ||||
|         /* ngl->out irqs are owned by the other end and should not be freed | ||||
|          * here | ||||
|          */ | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void device_class_base_init(ObjectClass *class, void *data) | ||||
|   | ||||
| @@ -243,12 +243,12 @@ static const MemoryRegionOps gpio_ops = { | ||||
| static struct cris_load_info li; | ||||
|  | ||||
| static | ||||
| void axisdev88_init(QEMUMachineInitArgs *args) | ||||
| void axisdev88_init(MachineState *machine) | ||||
| { | ||||
|     ram_addr_t ram_size = args->ram_size; | ||||
|     const char *cpu_model = args->cpu_model; | ||||
|     const char *kernel_filename = args->kernel_filename; | ||||
|     const char *kernel_cmdline = args->kernel_cmdline; | ||||
|     ram_addr_t ram_size = machine->ram_size; | ||||
|     const char *cpu_model = machine->cpu_model; | ||||
|     const char *kernel_filename = machine->kernel_filename; | ||||
|     const char *kernel_cmdline = machine->kernel_cmdline; | ||||
|     CRISCPU *cpu; | ||||
|     CPUCRISState *env; | ||||
|     DeviceState *dev; | ||||
|   | ||||
| @@ -177,7 +177,7 @@ static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size) | ||||
|         /* monitor ID 6, board type = 1 (color) */ | ||||
|         val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR; | ||||
|         break; | ||||
|     case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE: | ||||
|     case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1: | ||||
|         val = s->regs[addr - 0x10]; | ||||
|         break; | ||||
|     default: | ||||
| @@ -247,7 +247,7 @@ static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val, | ||||
|             qemu_irq_lower(s->irq); | ||||
|         } | ||||
|         break; | ||||
|     case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE: | ||||
|     case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1: | ||||
|         s->regs[addr - 0x10] = val; | ||||
|         break; | ||||
|     default: | ||||
| @@ -274,6 +274,20 @@ static const GraphicHwOps cg3_ops = { | ||||
|     .gfx_update = cg3_update_display, | ||||
| }; | ||||
|  | ||||
| static void cg3_initfn(Object *obj) | ||||
| { | ||||
|     SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | ||||
|     CG3State *s = CG3(obj); | ||||
|  | ||||
|     memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE); | ||||
|     memory_region_set_readonly(&s->rom, true); | ||||
|     sysbus_init_mmio(sbd, &s->rom); | ||||
|  | ||||
|     memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg", | ||||
|                           CG3_REG_SIZE); | ||||
|     sysbus_init_mmio(sbd, &s->reg); | ||||
| } | ||||
|  | ||||
| static void cg3_realizefn(DeviceState *dev, Error **errp) | ||||
| { | ||||
|     SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | ||||
| @@ -282,11 +296,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) | ||||
|     char *fcode_filename; | ||||
|  | ||||
|     /* FCode ROM */ | ||||
|     memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE); | ||||
|     vmstate_register_ram_global(&s->rom); | ||||
|     memory_region_set_readonly(&s->rom, true); | ||||
|     sysbus_init_mmio(sbd, &s->rom); | ||||
|  | ||||
|     fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE); | ||||
|     if (fcode_filename) { | ||||
|         ret = load_image_targphys(fcode_filename, s->prom_addr, | ||||
| @@ -296,10 +306,6 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg", | ||||
|                           CG3_REG_SIZE); | ||||
|     sysbus_init_mmio(sbd, &s->reg); | ||||
|  | ||||
|     memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size); | ||||
|     vmstate_register_ram_global(&s->vram_mem); | ||||
|     sysbus_init_mmio(sbd, &s->vram_mem); | ||||
| @@ -374,6 +380,7 @@ static const TypeInfo cg3_info = { | ||||
|     .name          = TYPE_CG3, | ||||
|     .parent        = TYPE_SYS_BUS_DEVICE, | ||||
|     .instance_size = sizeof(CG3State), | ||||
|     .instance_init = cg3_initfn, | ||||
|     .class_init    = cg3_class_init, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -173,6 +173,7 @@ static void jazz_led_update_display(void *opaque) | ||||
|             case 16: | ||||
|                 color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa); | ||||
|                 color_led = rgb_to_pixel16(0x00, 0xff, 0x00); | ||||
|                 break; | ||||
|             case 24: | ||||
|                 color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa); | ||||
|                 color_led = rgb_to_pixel24(0x00, 0xff, 0x00); | ||||
|   | ||||
| @@ -50,7 +50,7 @@ static void glue(draw_line2_, DEPTH)(void *opaque, | ||||
|     uint8_t v, r, g, b; | ||||
|  | ||||
|     do { | ||||
|         v = ldub_raw((void *) s); | ||||
|         v = ldub_p((void *) s); | ||||
|         r = (pal[v & 3] >> 4) & 0xf0; | ||||
|         g = pal[v & 3] & 0xf0; | ||||
|         b = (pal[v & 3] << 4) & 0xf0; | ||||
| @@ -89,7 +89,7 @@ static void glue(draw_line4_, DEPTH)(void *opaque, | ||||
|     uint8_t v, r, g, b; | ||||
|  | ||||
|     do { | ||||
|         v = ldub_raw((void *) s); | ||||
|         v = ldub_p((void *) s); | ||||
|         r = (pal[v & 0xf] >> 4) & 0xf0; | ||||
|         g = pal[v & 0xf] & 0xf0; | ||||
|         b = (pal[v & 0xf] << 4) & 0xf0; | ||||
| @@ -116,7 +116,7 @@ static void glue(draw_line8_, DEPTH)(void *opaque, | ||||
|     uint8_t v, r, g, b; | ||||
|  | ||||
|     do { | ||||
|         v = ldub_raw((void *) s); | ||||
|         v = ldub_p((void *) s); | ||||
|         r = (pal[v] >> 4) & 0xf0; | ||||
|         g = pal[v] & 0xf0; | ||||
|         b = (pal[v] << 4) & 0xf0; | ||||
| @@ -136,7 +136,7 @@ static void glue(draw_line12_, DEPTH)(void *opaque, | ||||
|     uint8_t r, g, b; | ||||
|  | ||||
|     do { | ||||
|         v = lduw_raw((void *) s); | ||||
|         v = lduw_p((void *) s); | ||||
|         r = (v >> 4) & 0xf0; | ||||
|         g = v & 0xf0; | ||||
|         b = (v << 4) & 0xf0; | ||||
| @@ -159,7 +159,7 @@ static void glue(draw_line16_, DEPTH)(void *opaque, | ||||
|     uint8_t r, g, b; | ||||
|  | ||||
|     do { | ||||
|         v = lduw_raw((void *) s); | ||||
|         v = lduw_p((void *) s); | ||||
|         r = (v >> 8) & 0xf8; | ||||
|         g = (v >> 3) & 0xfc; | ||||
|         b = (v << 3) & 0xf8; | ||||
|   | ||||
| @@ -620,17 +620,6 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) | ||||
|             src += 2; | ||||
|             break; | ||||
|         case 1: /* 16 bpp plus transparency */ | ||||
|             alpha = *(uint16_t *) src & (1 << 24); | ||||
|             if (s->control[0] & LCCR0_CMS) | ||||
|                 r = g = b = *(uint16_t *) src & 0xff; | ||||
|             else { | ||||
|                 r = (*(uint16_t *) src & 0xf800) >> 8; | ||||
|                 g = (*(uint16_t *) src & 0x07e0) >> 3; | ||||
|                 b = (*(uint16_t *) src & 0x001f) << 3; | ||||
|             } | ||||
|             src += 2; | ||||
|             break; | ||||
|         case 2: /* 18 bpp plus transparency */ | ||||
|             alpha = *(uint32_t *) src & (1 << 24); | ||||
|             if (s->control[0] & LCCR0_CMS) | ||||
|                 r = g = b = *(uint32_t *) src & 0xff; | ||||
| @@ -641,6 +630,17 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) | ||||
|             } | ||||
|             src += 4; | ||||
|             break; | ||||
|         case 2: /* 18 bpp plus transparency */ | ||||
|             alpha = *(uint32_t *) src & (1 << 24); | ||||
|             if (s->control[0] & LCCR0_CMS) | ||||
|                 r = g = b = *(uint32_t *) src & 0xff; | ||||
|             else { | ||||
|                 r = (*(uint32_t *) src & 0xfc0000) >> 16; | ||||
|                 g = (*(uint32_t *) src & 0x00fc00) >> 8; | ||||
|                 b = (*(uint32_t *) src & 0x0000fc); | ||||
|             } | ||||
|             src += 4; | ||||
|             break; | ||||
|         case 3: /* 24 bpp plus transparency */ | ||||
|             alpha = *(uint32_t *) src & (1 << 24); | ||||
|             if (s->control[0] & LCCR0_CMS) | ||||
|   | ||||
| @@ -47,7 +47,7 @@ static void glue(draw_line8_, PIXEL_NAME)( | ||||
| { | ||||
|     uint8_t v, r, g, b; | ||||
|     do { | ||||
|       	v = ldub_raw(s); | ||||
| 	v = ldub_p(s); | ||||
| 	r = (pal[v] >> 16) & 0xff; | ||||
| 	g = (pal[v] >>  8) & 0xff; | ||||
| 	b = (pal[v] >>  0) & 0xff; | ||||
| @@ -64,7 +64,7 @@ static void glue(draw_line16_, PIXEL_NAME)( | ||||
|     uint8_t r, g, b; | ||||
|  | ||||
|     do { | ||||
| 	rgb565 = lduw_raw(s); | ||||
| 	rgb565 = lduw_p(s); | ||||
| 	r = ((rgb565 >> 11) & 0x1f) << 3; | ||||
| 	g = ((rgb565 >>  5) & 0x3f) << 2; | ||||
| 	b = ((rgb565 >>  0) & 0x1f) << 3; | ||||
| @@ -80,7 +80,7 @@ static void glue(draw_line32_, PIXEL_NAME)( | ||||
|     uint8_t r, g, b; | ||||
|  | ||||
|     do { | ||||
| 	ldub_raw(s); | ||||
| 	ldub_p(s); | ||||
| #if defined(TARGET_WORDS_BIGENDIAN) | ||||
|         r = s[1]; | ||||
|         g = s[2]; | ||||
|   | ||||
| @@ -530,8 +530,36 @@ static const GraphicHwOps tcx24_ops = { | ||||
|     .gfx_update = tcx24_update_display, | ||||
| }; | ||||
|  | ||||
| static int tcx_init1(SysBusDevice *dev) | ||||
| static void tcx_initfn(Object *obj) | ||||
| { | ||||
|     SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | ||||
|     TCXState *s = TCX(obj); | ||||
|  | ||||
|     memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE); | ||||
|     memory_region_set_readonly(&s->rom, true); | ||||
|     sysbus_init_mmio(sbd, &s->rom); | ||||
|  | ||||
|     /* DAC */ | ||||
|     memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, | ||||
|                           "tcx.dac", TCX_DAC_NREGS); | ||||
|     sysbus_init_mmio(sbd, &s->dac); | ||||
|  | ||||
|     /* TEC (dummy) */ | ||||
|     memory_region_init_io(&s->tec, OBJECT(s), &dummy_ops, s, | ||||
|                           "tcx.tec", TCX_TEC_NREGS); | ||||
|     sysbus_init_mmio(sbd, &s->tec); | ||||
|  | ||||
|     /* THC: NetBSD writes here even with 8-bit display: dummy */ | ||||
|     memory_region_init_io(&s->thc24, OBJECT(s), &dummy_ops, s, "tcx.thc24", | ||||
|                           TCX_THC_NREGS_24); | ||||
|     sysbus_init_mmio(sbd, &s->thc24); | ||||
|  | ||||
|     return; | ||||
| } | ||||
|  | ||||
| static void tcx_realizefn(DeviceState *dev, Error **errp) | ||||
| { | ||||
|     SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | ||||
|     TCXState *s = TCX(dev); | ||||
|     ram_addr_t vram_offset = 0; | ||||
|     int size, ret; | ||||
| @@ -544,18 +572,13 @@ static int tcx_init1(SysBusDevice *dev) | ||||
|     vram_base = memory_region_get_ram_ptr(&s->vram_mem); | ||||
|  | ||||
|     /* FCode ROM */ | ||||
|     memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE); | ||||
|     vmstate_register_ram_global(&s->rom); | ||||
|     memory_region_set_readonly(&s->rom, true); | ||||
|     sysbus_init_mmio(dev, &s->rom); | ||||
|  | ||||
|     fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE); | ||||
|     if (fcode_filename) { | ||||
|         ret = load_image_targphys(fcode_filename, s->prom_addr, | ||||
|                                   FCODE_MAX_ROM_SIZE); | ||||
|         if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { | ||||
|             fprintf(stderr, "tcx: could not load prom '%s'\n", TCX_ROM_FILE); | ||||
|             return -1; | ||||
|             error_report("tcx: could not load prom '%s'", TCX_ROM_FILE); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -564,24 +587,10 @@ static int tcx_init1(SysBusDevice *dev) | ||||
|     size = s->vram_size; | ||||
|     memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit", | ||||
|                              &s->vram_mem, vram_offset, size); | ||||
|     sysbus_init_mmio(dev, &s->vram_8bit); | ||||
|     sysbus_init_mmio(sbd, &s->vram_8bit); | ||||
|     vram_offset += size; | ||||
|     vram_base += size; | ||||
|  | ||||
|     /* DAC */ | ||||
|     memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, | ||||
|                           "tcx.dac", TCX_DAC_NREGS); | ||||
|     sysbus_init_mmio(dev, &s->dac); | ||||
|  | ||||
|     /* TEC (dummy) */ | ||||
|     memory_region_init_io(&s->tec, OBJECT(s), &dummy_ops, s, | ||||
|                           "tcx.tec", TCX_TEC_NREGS); | ||||
|     sysbus_init_mmio(dev, &s->tec); | ||||
|     /* THC: NetBSD writes here even with 8-bit display: dummy */ | ||||
|     memory_region_init_io(&s->thc24, OBJECT(s), &dummy_ops, s, "tcx.thc24", | ||||
|                           TCX_THC_NREGS_24); | ||||
|     sysbus_init_mmio(dev, &s->thc24); | ||||
|  | ||||
|     if (s->depth == 24) { | ||||
|         /* 24-bit plane */ | ||||
|         size = s->vram_size * 4; | ||||
| @@ -589,7 +598,7 @@ static int tcx_init1(SysBusDevice *dev) | ||||
|         s->vram24_offset = vram_offset; | ||||
|         memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", | ||||
|                                  &s->vram_mem, vram_offset, size); | ||||
|         sysbus_init_mmio(dev, &s->vram_24bit); | ||||
|         sysbus_init_mmio(sbd, &s->vram_24bit); | ||||
|         vram_offset += size; | ||||
|         vram_base += size; | ||||
|  | ||||
| @@ -599,20 +608,19 @@ static int tcx_init1(SysBusDevice *dev) | ||||
|         s->cplane_offset = vram_offset; | ||||
|         memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", | ||||
|                                  &s->vram_mem, vram_offset, size); | ||||
|         sysbus_init_mmio(dev, &s->vram_cplane); | ||||
|         sysbus_init_mmio(sbd, &s->vram_cplane); | ||||
|  | ||||
|         s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); | ||||
|     } else { | ||||
|         /* THC 8 bit (dummy) */ | ||||
|         memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8", | ||||
|                               TCX_THC_NREGS_8); | ||||
|         sysbus_init_mmio(dev, &s->thc8); | ||||
|         sysbus_init_mmio(sbd, &s->thc8); | ||||
|  | ||||
|         s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); | ||||
|     } | ||||
|  | ||||
|     qemu_console_resize(s->con, s->width, s->height); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static Property tcx_properties[] = { | ||||
| @@ -627,9 +635,8 @@ static Property tcx_properties[] = { | ||||
| static void tcx_class_init(ObjectClass *klass, void *data) | ||||
| { | ||||
|     DeviceClass *dc = DEVICE_CLASS(klass); | ||||
|     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); | ||||
|  | ||||
|     k->init = tcx_init1; | ||||
|     dc->realize = tcx_realizefn; | ||||
|     dc->reset = tcx_reset; | ||||
|     dc->vmsd = &vmstate_tcx; | ||||
|     dc->props = tcx_properties; | ||||
| @@ -639,6 +646,7 @@ static const TypeInfo tcx_info = { | ||||
|     .name          = TYPE_TCX, | ||||
|     .parent        = TYPE_SYS_BUS_DEVICE, | ||||
|     .instance_size = sizeof(TCXState), | ||||
|     .instance_init = tcx_initfn, | ||||
|     .class_init    = tcx_class_init, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -361,7 +361,7 @@ static void glue(vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d, | ||||
|  | ||||
|     w = width; | ||||
|     do { | ||||
|         v = lduw_raw((void *)s); | ||||
|         v = lduw_p((void *)s); | ||||
|         r = (v >> 7) & 0xf8; | ||||
|         g = (v >> 2) & 0xf8; | ||||
|         b = (v << 3) & 0xf8; | ||||
| @@ -386,7 +386,7 @@ static void glue(vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d, | ||||
|  | ||||
|     w = width; | ||||
|     do { | ||||
|         v = lduw_raw((void *)s); | ||||
|         v = lduw_p((void *)s); | ||||
|         r = (v >> 8) & 0xf8; | ||||
|         g = (v >> 3) & 0xfc; | ||||
|         b = (v << 3) & 0xf8; | ||||
|   | ||||
| @@ -863,7 +863,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) | ||||
|         break; | ||||
|  | ||||
|     case SVGA_REG_CURSOR_Y: | ||||
|         ret = s->cursor.x; | ||||
|         ret = s->cursor.y; | ||||
|         break; | ||||
|  | ||||
|     case SVGA_REG_CURSOR_ON: | ||||
|   | ||||
| @@ -157,11 +157,6 @@ static inline int stream_running(struct Stream *s) | ||||
|     return s->regs[R_DMACR] & DMACR_RUNSTOP; | ||||
| } | ||||
|  | ||||
| static inline int stream_halted(struct Stream *s) | ||||
| { | ||||
|     return s->regs[R_DMASR] & DMASR_HALTED; | ||||
| } | ||||
|  | ||||
| static inline int stream_idle(struct Stream *s) | ||||
| { | ||||
|     return !!(s->regs[R_DMASR] & DMASR_IDLE); | ||||
|   | ||||
| @@ -14,8 +14,10 @@ | ||||
|  */ | ||||
|  | ||||
| #include "qemu-common.h" | ||||
| #include "qemu/host-utils.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "sysemu/kvm.h" | ||||
| #include "sysemu/cpus.h" | ||||
| #include "hw/sysbus.h" | ||||
| #include "hw/kvm/clock.h" | ||||
|  | ||||
| @@ -34,6 +36,48 @@ typedef struct KVMClockState { | ||||
|     bool clock_valid; | ||||
| } KVMClockState; | ||||
|  | ||||
| struct pvclock_vcpu_time_info { | ||||
|     uint32_t   version; | ||||
|     uint32_t   pad0; | ||||
|     uint64_t   tsc_timestamp; | ||||
|     uint64_t   system_time; | ||||
|     uint32_t   tsc_to_system_mul; | ||||
|     int8_t     tsc_shift; | ||||
|     uint8_t    flags; | ||||
|     uint8_t    pad[2]; | ||||
| } __attribute__((__packed__)); /* 32 bytes */ | ||||
|  | ||||
| static uint64_t kvmclock_current_nsec(KVMClockState *s) | ||||
| { | ||||
|     CPUState *cpu = first_cpu; | ||||
|     CPUX86State *env = cpu->env_ptr; | ||||
|     hwaddr kvmclock_struct_pa = env->system_time_msr & ~1ULL; | ||||
|     uint64_t migration_tsc = env->tsc; | ||||
|     struct pvclock_vcpu_time_info time; | ||||
|     uint64_t delta; | ||||
|     uint64_t nsec_lo; | ||||
|     uint64_t nsec_hi; | ||||
|     uint64_t nsec; | ||||
|  | ||||
|     if (!(env->system_time_msr & 1ULL)) { | ||||
|         /* KVM clock not active */ | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     cpu_physical_memory_read(kvmclock_struct_pa, &time, sizeof(time)); | ||||
|  | ||||
|     assert(time.tsc_timestamp <= migration_tsc); | ||||
|     delta = migration_tsc - time.tsc_timestamp; | ||||
|     if (time.tsc_shift < 0) { | ||||
|         delta >>= -time.tsc_shift; | ||||
|     } else { | ||||
|         delta <<= time.tsc_shift; | ||||
|     } | ||||
|  | ||||
|     mulu64(&nsec_lo, &nsec_hi, delta, time.tsc_to_system_mul); | ||||
|     nsec = (nsec_lo >> 32) | (nsec_hi << 32); | ||||
|     return nsec + time.system_time; | ||||
| } | ||||
|  | ||||
| static void kvmclock_vm_state_change(void *opaque, int running, | ||||
|                                      RunState state) | ||||
| @@ -45,9 +89,15 @@ static void kvmclock_vm_state_change(void *opaque, int running, | ||||
|  | ||||
|     if (running) { | ||||
|         struct kvm_clock_data data; | ||||
|         uint64_t time_at_migration = kvmclock_current_nsec(s); | ||||
|  | ||||
|         s->clock_valid = false; | ||||
|  | ||||
| 	/* We can't rely on the migrated clock value, just discard it */ | ||||
| 	if (time_at_migration) { | ||||
| 	        s->clock = time_at_migration; | ||||
| 	} | ||||
|  | ||||
|         data.clock = s->clock; | ||||
|         data.flags = 0; | ||||
|         ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data); | ||||
| @@ -75,6 +125,8 @@ static void kvmclock_vm_state_change(void *opaque, int running, | ||||
|         if (s->clock_valid) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         cpu_synchronize_all_states(); | ||||
|         ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); | ||||
|         if (ret < 0) { | ||||
|             fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); | ||||
|   | ||||
| @@ -922,9 +922,6 @@ static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, | ||||
|                                               0x280, 0x380 }; | ||||
| static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; | ||||
|  | ||||
| static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; | ||||
| static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; | ||||
|  | ||||
| void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd) | ||||
| { | ||||
|     static int nb_ne2k = 0; | ||||
|   | ||||
| @@ -69,7 +69,7 @@ static bool smbios_legacy_mode; | ||||
| static bool gigabyte_align = true; | ||||
|  | ||||
| /* PC hardware initialisation */ | ||||
| static void pc_init1(QEMUMachineInitArgs *args, | ||||
| static void pc_init1(MachineState *machine, | ||||
|                      int pci_enabled, | ||||
|                      int kvmclock_enabled) | ||||
| { | ||||
| @@ -106,7 +106,7 @@ static void pc_init1(QEMUMachineInitArgs *args, | ||||
|     object_property_add_child(qdev_get_machine(), "icc-bridge", | ||||
|                               OBJECT(icc_bridge), NULL); | ||||
|  | ||||
|     pc_cpus_init(args->cpu_model, icc_bridge); | ||||
|     pc_cpus_init(machine->cpu_model, icc_bridge); | ||||
|  | ||||
|     if (kvm_enabled() && kvmclock_enabled) { | ||||
|         kvmclock_create(); | ||||
| @@ -119,13 +119,13 @@ static void pc_init1(QEMUMachineInitArgs *args, | ||||
|      * For old machine types, use whatever split we used historically to avoid | ||||
|      * breaking migration. | ||||
|      */ | ||||
|     if (args->ram_size >= 0xe0000000) { | ||||
|     if (machine->ram_size >= 0xe0000000) { | ||||
|         ram_addr_t lowmem = gigabyte_align ? 0xc0000000 : 0xe0000000; | ||||
|         above_4g_mem_size = args->ram_size - lowmem; | ||||
|         above_4g_mem_size = machine->ram_size - lowmem; | ||||
|         below_4g_mem_size = lowmem; | ||||
|     } else { | ||||
|         above_4g_mem_size = 0; | ||||
|         below_4g_mem_size = args->ram_size; | ||||
|         below_4g_mem_size = machine->ram_size; | ||||
|     } | ||||
|  | ||||
|     if (pci_enabled) { | ||||
| @@ -145,16 +145,17 @@ static void pc_init1(QEMUMachineInitArgs *args, | ||||
|     guest_info->isapc_ram_fw = !pci_enabled; | ||||
|  | ||||
|     if (smbios_defaults) { | ||||
|         MachineClass *mc = MACHINE_GET_CLASS(machine); | ||||
|         /* These values are guest ABI, do not change */ | ||||
|         smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", | ||||
|                             args->machine->name, smbios_legacy_mode); | ||||
|                             mc->name, smbios_legacy_mode); | ||||
|     } | ||||
|  | ||||
|     /* allocate ram and load rom/bios */ | ||||
|     if (!xen_enabled()) { | ||||
|         fw_cfg = pc_memory_init(system_memory, | ||||
|                        args->kernel_filename, args->kernel_cmdline, | ||||
|                        args->initrd_filename, | ||||
|                        machine->kernel_filename, machine->kernel_cmdline, | ||||
|                        machine->initrd_filename, | ||||
|                        below_4g_mem_size, above_4g_mem_size, | ||||
|                        rom_memory, &ram_memory, guest_info); | ||||
|     } | ||||
| @@ -170,7 +171,7 @@ static void pc_init1(QEMUMachineInitArgs *args, | ||||
|  | ||||
|     if (pci_enabled) { | ||||
|         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, | ||||
|                               system_memory, system_io, args->ram_size, | ||||
|                               system_memory, system_io, machine->ram_size, | ||||
|                               below_4g_mem_size, | ||||
|                               above_4g_mem_size, | ||||
|                               pci_memory, ram_memory); | ||||
| @@ -235,7 +236,7 @@ static void pc_init1(QEMUMachineInitArgs *args, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_order, | ||||
|     pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order, | ||||
|                  floppy, idebus[0], idebus[1], rtc_state); | ||||
|  | ||||
|     if (pci_enabled && usb_enabled(false)) { | ||||
| @@ -258,131 +259,131 @@ static void pc_init1(QEMUMachineInitArgs *args, | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void pc_init_pci(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci(MachineState *machine) | ||||
| { | ||||
|     pc_init1(args, 1, 1); | ||||
|     pc_init1(machine, 1, 1); | ||||
| } | ||||
|  | ||||
| static void pc_compat_2_0(QEMUMachineInitArgs *args) | ||||
| static void pc_compat_2_0(MachineState *machine) | ||||
| { | ||||
|     smbios_legacy_mode = true; | ||||
| } | ||||
|  | ||||
| static void pc_compat_1_7(QEMUMachineInitArgs *args) | ||||
| static void pc_compat_1_7(MachineState *machine) | ||||
| { | ||||
|     pc_compat_2_0(args); | ||||
|     pc_compat_2_0(machine); | ||||
|     smbios_defaults = false; | ||||
|     gigabyte_align = false; | ||||
|     option_rom_has_mr = true; | ||||
|     x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC); | ||||
| } | ||||
|  | ||||
| static void pc_compat_1_6(QEMUMachineInitArgs *args) | ||||
| static void pc_compat_1_6(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_7(args); | ||||
|     pc_compat_1_7(machine); | ||||
|     has_pci_info = false; | ||||
|     rom_file_has_mr = false; | ||||
|     has_acpi_build = false; | ||||
| } | ||||
|  | ||||
| static void pc_compat_1_5(QEMUMachineInitArgs *args) | ||||
| static void pc_compat_1_5(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_6(args); | ||||
|     pc_compat_1_6(machine); | ||||
| } | ||||
|  | ||||
| static void pc_compat_1_4(QEMUMachineInitArgs *args) | ||||
| static void pc_compat_1_4(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_5(args); | ||||
|     pc_compat_1_5(machine); | ||||
|     x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); | ||||
|     x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); | ||||
| } | ||||
|  | ||||
| static void pc_compat_1_3(QEMUMachineInitArgs *args) | ||||
| static void pc_compat_1_3(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_4(args); | ||||
|     pc_compat_1_4(machine); | ||||
|     enable_compat_apic_id_mode(); | ||||
| } | ||||
|  | ||||
| /* PC compat function for pc-0.14 to pc-1.2 */ | ||||
| static void pc_compat_1_2(QEMUMachineInitArgs *args) | ||||
| static void pc_compat_1_2(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_3(args); | ||||
|     pc_compat_1_3(machine); | ||||
|     x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); | ||||
| } | ||||
|  | ||||
| static void pc_init_pci_2_0(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci_2_0(MachineState *machine) | ||||
| { | ||||
|     pc_compat_2_0(args); | ||||
|     pc_init_pci(args); | ||||
|     pc_compat_2_0(machine); | ||||
|     pc_init_pci(machine); | ||||
| } | ||||
|  | ||||
| static void pc_init_pci_1_7(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci_1_7(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_7(args); | ||||
|     pc_init_pci(args); | ||||
|     pc_compat_1_7(machine); | ||||
|     pc_init_pci(machine); | ||||
| } | ||||
|  | ||||
| static void pc_init_pci_1_6(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci_1_6(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_6(args); | ||||
|     pc_init_pci(args); | ||||
|     pc_compat_1_6(machine); | ||||
|     pc_init_pci(machine); | ||||
| } | ||||
|  | ||||
| static void pc_init_pci_1_5(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci_1_5(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_5(args); | ||||
|     pc_init_pci(args); | ||||
|     pc_compat_1_5(machine); | ||||
|     pc_init_pci(machine); | ||||
| } | ||||
|  | ||||
| static void pc_init_pci_1_4(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci_1_4(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_4(args); | ||||
|     pc_init_pci(args); | ||||
|     pc_compat_1_4(machine); | ||||
|     pc_init_pci(machine); | ||||
| } | ||||
|  | ||||
| static void pc_init_pci_1_3(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci_1_3(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_3(args); | ||||
|     pc_init_pci(args); | ||||
|     pc_compat_1_3(machine); | ||||
|     pc_init_pci(machine); | ||||
| } | ||||
|  | ||||
| /* PC machine init function for pc-0.14 to pc-1.2 */ | ||||
| static void pc_init_pci_1_2(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci_1_2(MachineState *machine) | ||||
| { | ||||
|     pc_compat_1_2(args); | ||||
|     pc_init_pci(args); | ||||
|     pc_compat_1_2(machine); | ||||
|     pc_init_pci(machine); | ||||
| } | ||||
|  | ||||
| /* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */ | ||||
| static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) | ||||
| static void pc_init_pci_no_kvmclock(MachineState *machine) | ||||
| { | ||||
|     has_pci_info = false; | ||||
|     has_acpi_build = false; | ||||
|     smbios_defaults = false; | ||||
|     x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); | ||||
|     enable_compat_apic_id_mode(); | ||||
|     pc_init1(args, 1, 0); | ||||
|     pc_init1(machine, 1, 0); | ||||
| } | ||||
|  | ||||
| static void pc_init_isa(QEMUMachineInitArgs *args) | ||||
| static void pc_init_isa(MachineState *machine) | ||||
| { | ||||
|     has_pci_info = false; | ||||
|     has_acpi_build = false; | ||||
|     smbios_defaults = false; | ||||
|     if (!args->cpu_model) { | ||||
|         args->cpu_model = "486"; | ||||
|     if (!machine->cpu_model) { | ||||
|         machine->cpu_model = "486"; | ||||
|     } | ||||
|     x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); | ||||
|     enable_compat_apic_id_mode(); | ||||
|     pc_init1(args, 0, 1); | ||||
|     pc_init1(machine, 0, 1); | ||||
| } | ||||
|  | ||||
| #ifdef CONFIG_XEN | ||||
| static void pc_xen_hvm_init(QEMUMachineInitArgs *args) | ||||
| static void pc_xen_hvm_init(MachineState *machine) | ||||
| { | ||||
|     PCIBus *bus; | ||||
|  | ||||
|     pc_init_pci(args); | ||||
|     pc_init_pci(machine); | ||||
|  | ||||
|     bus = pci_find_primary_bus(); | ||||
|     if (bus != NULL) { | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user