Compare commits
	
		
			341 Commits
		
	
	
		
			v1.1-rc0
			...
			v0.12.5-qe
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					69903f803a | ||
| 
						 | 
					174f225e9d | ||
| 
						 | 
					e916448940 | ||
| 
						 | 
					bb44e0bbce | ||
| 
						 | 
					191d44fc43 | ||
| 
						 | 
					a2f0cbaa58 | ||
| 
						 | 
					a9d9a66f13 | ||
| 
						 | 
					37060c28e5 | ||
| 
						 | 
					7205c21e76 | ||
| 
						 | 
					ceef722d01 | ||
| 
						 | 
					dfe0bb55ee | ||
| 
						 | 
					6fd82592ce | ||
| 
						 | 
					39187b5192 | ||
| 
						 | 
					729862401d | ||
| 
						 | 
					34d0d68bdf | ||
| 
						 | 
					82e9cbeb0d | ||
| 
						 | 
					2020dd5535 | ||
| 
						 | 
					0c0f53e25c | ||
| 
						 | 
					3dbe0714dd | ||
| 
						 | 
					9067bac11d | ||
| 
						 | 
					74471f3742 | ||
| 
						 | 
					370f80376a | ||
| 
						 | 
					ed3aac289a | ||
| 
						 | 
					11b52a6536 | ||
| 
						 | 
					b6185fc79c | ||
| 
						 | 
					8fd7d5438e | ||
| 
						 | 
					a513171f80 | ||
| 
						 | 
					ff9e177617 | ||
| 
						 | 
					db3519a9ec | ||
| 
						 | 
					258e351d12 | ||
| 
						 | 
					cd14f4d346 | ||
| 
						 | 
					df631629b1 | ||
| 
						 | 
					af0269b036 | ||
| 
						 | 
					d37dbf988d | ||
| 
						 | 
					cc7ed88f28 | ||
| 
						 | 
					07442ab4a1 | ||
| 
						 | 
					dbe6a18d82 | ||
| 
						 | 
					7dd007c2ed | ||
| 
						 | 
					9c6a8f503d | ||
| 
						 | 
					0c459361a1 | ||
| 
						 | 
					72d3457e8d | ||
| 
						 | 
					e1f0c1d05d | ||
| 
						 | 
					74bcc51b99 | ||
| 
						 | 
					7e4f956056 | ||
| 
						 | 
					1fb9798b69 | ||
| 
						 | 
					9f6a84bc43 | ||
| 
						 | 
					8cef921d18 | ||
| 
						 | 
					b04c3db504 | ||
| 
						 | 
					d04d7cf158 | ||
| 
						 | 
					2b8bdd5c7f | ||
| 
						 | 
					2a44494726 | ||
| 
						 | 
					8f30db54d9 | ||
| 
						 | 
					b09ac1abe7 | ||
| 
						 | 
					012d4869c1 | ||
| 
						 | 
					3597c9c1d5 | ||
| 
						 | 
					3b4bef0696 | ||
| 
						 | 
					d899303743 | ||
| 
						 | 
					5773685183 | ||
| 
						 | 
					d40ba77ebf | ||
| 
						 | 
					a8c46d182c | ||
| 
						 | 
					d80e20a1c3 | ||
| 
						 | 
					1ce4fad939 | ||
| 
						 | 
					9167a242db | ||
| 
						 | 
					09e96924ec | ||
| 
						 | 
					69ff4e9dbd | ||
| 
						 | 
					0434349d6a | ||
| 
						 | 
					e007221223 | ||
| 
						 | 
					4622317288 | ||
| 
						 | 
					ffac613ff9 | ||
| 
						 | 
					aba5288247 | ||
| 
						 | 
					4f7cb96931 | ||
| 
						 | 
					fafc2e4b33 | ||
| 
						 | 
					83ef70f24a | ||
| 
						 | 
					de17c16e1f | ||
| 
						 | 
					9462695b64 | ||
| 
						 | 
					5eb089588e | ||
| 
						 | 
					2039f70c23 | ||
| 
						 | 
					082a9fc256 | ||
| 
						 | 
					36a013c956 | ||
| 
						 | 
					c4c4b32b81 | ||
| 
						 | 
					804b6ab08d | ||
| 
						 | 
					81b168a702 | ||
| 
						 | 
					5c6892078a | ||
| 
						 | 
					18a21890ff | ||
| 
						 | 
					6629fa6473 | ||
| 
						 | 
					2a7996ce0e | ||
| 
						 | 
					8ec131fb59 | ||
| 
						 | 
					30d061750d | ||
| 
						 | 
					c5f5dc5bad | ||
| 
						 | 
					d2df336c58 | ||
| 
						 | 
					b299b12b17 | ||
| 
						 | 
					c248df6161 | ||
| 
						 | 
					7d5625d5f7 | ||
| 
						 | 
					cc21d131e3 | ||
| 
						 | 
					41a5bda61f | ||
| 
						 | 
					5163f6e864 | ||
| 
						 | 
					6173d56bdc | ||
| 
						 | 
					f39942d217 | ||
| 
						 | 
					5dde87088f | ||
| 
						 | 
					3fa017e24b | ||
| 
						 | 
					35924dbe8c | ||
| 
						 | 
					88aa905668 | ||
| 
						 | 
					b93c5c84c8 | ||
| 
						 | 
					f203baee5b | ||
| 
						 | 
					5e3be62385 | ||
| 
						 | 
					b391493bc6 | ||
| 
						 | 
					57f9f4c9f5 | ||
| 
						 | 
					7ebc79037c | ||
| 
						 | 
					ea299062eb | ||
| 
						 | 
					e03dd1a6c2 | ||
| 
						 | 
					535d2eb34a | ||
| 
						 | 
					beb8eab90c | ||
| 
						 | 
					8d67694fbf | ||
| 
						 | 
					02510b2436 | ||
| 
						 | 
					b57a2297f2 | ||
| 
						 | 
					43fab08210 | ||
| 
						 | 
					915080e6b1 | ||
| 
						 | 
					9f59ddcc4f | ||
| 
						 | 
					999ceb2c1d | ||
| 
						 | 
					307331a42a | ||
| 
						 | 
					6728dd464b | ||
| 
						 | 
					bb45bcc8de | ||
| 
						 | 
					096109c804 | ||
| 
						 | 
					7ae1fcc88c | ||
| 
						 | 
					299e0bc52a | ||
| 
						 | 
					74f0529e24 | ||
| 
						 | 
					614971158c | ||
| 
						 | 
					afa328b1b2 | ||
| 
						 | 
					868dab5dc2 | ||
| 
						 | 
					29bb3bf350 | ||
| 
						 | 
					dbf45b44b7 | ||
| 
						 | 
					d0d888bc6d | ||
| 
						 | 
					19abbad0da | ||
| 
						 | 
					f48aba6de7 | ||
| 
						 | 
					cb2ae96bf6 | ||
| 
						 | 
					848f874ca1 | ||
| 
						 | 
					a1a86bf902 | ||
| 
						 | 
					c727a05459 | ||
| 
						 | 
					eb05143e24 | ||
| 
						 | 
					0c709e6195 | ||
| 
						 | 
					dc88aa49b4 | ||
| 
						 | 
					dc2ffbf6d8 | ||
| 
						 | 
					d3bf9367f2 | ||
| 
						 | 
					c502715a74 | ||
| 
						 | 
					b9a61d2154 | ||
| 
						 | 
					9525204c5d | ||
| 
						 | 
					f79d556b4f | ||
| 
						 | 
					41ae9ece21 | ||
| 
						 | 
					40480d2bf4 | ||
| 
						 | 
					e389e937a7 | ||
| 
						 | 
					73b48d914f | ||
| 
						 | 
					3999bf3244 | ||
| 
						 | 
					a3441a43a6 | ||
| 
						 | 
					49a3aaac4a | ||
| 
						 | 
					027866ce23 | ||
| 
						 | 
					04babf6c6f | ||
| 
						 | 
					d2b8117310 | ||
| 
						 | 
					0c4b9aef7b | ||
| 
						 | 
					431c829f33 | ||
| 
						 | 
					be7398ec06 | ||
| 
						 | 
					be59ce1f48 | ||
| 
						 | 
					eacad66dbe | ||
| 
						 | 
					66dbb62824 | ||
| 
						 | 
					d47d251286 | ||
| 
						 | 
					348af56fae | ||
| 
						 | 
					09866b9baa | ||
| 
						 | 
					e1daf40e3e | ||
| 
						 | 
					de3ea06d59 | ||
| 
						 | 
					fe46a160ce | ||
| 
						 | 
					8033c42abd | ||
| 
						 | 
					4713c69fa2 | ||
| 
						 | 
					d68bf60838 | ||
| 
						 | 
					57fa5ca551 | ||
| 
						 | 
					8610774f79 | ||
| 
						 | 
					76ba04832b | ||
| 
						 | 
					644f5de21b | ||
| 
						 | 
					dcc0da8297 | ||
| 
						 | 
					41193c50fa | ||
| 
						 | 
					da0266005a | ||
| 
						 | 
					eacdccbb3e | ||
| 
						 | 
					65e8c51928 | ||
| 
						 | 
					e470436f19 | ||
| 
						 | 
					b60c2c74f3 | ||
| 
						 | 
					fe1b69708c | ||
| 
						 | 
					a1678e85db | ||
| 
						 | 
					8212d18cf5 | ||
| 
						 | 
					6c412ddf1c | ||
| 
						 | 
					862ad4be53 | ||
| 
						 | 
					aac2ad563a | ||
| 
						 | 
					eb41f58a4e | ||
| 
						 | 
					5543b41167 | ||
| 
						 | 
					31d85f6a6b | ||
| 
						 | 
					9c49a2533c | ||
| 
						 | 
					c6faf5fd73 | ||
| 
						 | 
					069def25cb | ||
| 
						 | 
					3733a1e804 | ||
| 
						 | 
					5b06a3f785 | ||
| 
						 | 
					baaf73aaac | ||
| 
						 | 
					345c22aa80 | ||
| 
						 | 
					26bb2a0865 | ||
| 
						 | 
					e6ea832410 | ||
| 
						 | 
					22d0cc8d38 | ||
| 
						 | 
					898829d5c7 | ||
| 
						 | 
					72bb3c7571 | ||
| 
						 | 
					48c437f0ab | ||
| 
						 | 
					07d00c2174 | ||
| 
						 | 
					3243a06f51 | ||
| 
						 | 
					1c3f96be38 | ||
| 
						 | 
					df9e7219db | ||
| 
						 | 
					e83421f511 | ||
| 
						 | 
					2b311b3cce | ||
| 
						 | 
					4b5db3749c | ||
| 
						 | 
					a1497a782c | ||
| 
						 | 
					3c547d7bb7 | ||
| 
						 | 
					3b43502e3a | ||
| 
						 | 
					078517421f | ||
| 
						 | 
					afc7055619 | ||
| 
						 | 
					53425683d4 | ||
| 
						 | 
					ef5a63186a | ||
| 
						 | 
					4a0e0accd7 | ||
| 
						 | 
					73e47683de | ||
| 
						 | 
					115e94a31e | ||
| 
						 | 
					5fd5f6999d | ||
| 
						 | 
					602e97b725 | ||
| 
						 | 
					97b766dfcd | ||
| 
						 | 
					fb8cf78db6 | ||
| 
						 | 
					c5238ac21b | ||
| 
						 | 
					99917a99cd | ||
| 
						 | 
					55ed56908f | ||
| 
						 | 
					139e310025 | ||
| 
						 | 
					bed93b1dcb | ||
| 
						 | 
					73b4ac5cd8 | ||
| 
						 | 
					00e8277b83 | ||
| 
						 | 
					a8ea3a357b | ||
| 
						 | 
					f8051485c1 | ||
| 
						 | 
					807c80b259 | ||
| 
						 | 
					686a3c3dc2 | ||
| 
						 | 
					a381d8277c | ||
| 
						 | 
					8647b09bfd | ||
| 
						 | 
					9153014fa0 | ||
| 
						 | 
					f6d4446ea8 | ||
| 
						 | 
					f1e247ee6b | ||
| 
						 | 
					a49668769d | ||
| 
						 | 
					97d949d9da | ||
| 
						 | 
					040093b1a5 | ||
| 
						 | 
					5d4e53dc81 | ||
| 
						 | 
					3ebee80226 | ||
| 
						 | 
					c56651312b | ||
| 
						 | 
					869ca150e7 | ||
| 
						 | 
					910628f396 | ||
| 
						 | 
					251241dc90 | ||
| 
						 | 
					03a23e5c6e | ||
| 
						 | 
					a68fc29ceb | ||
| 
						 | 
					0014803d23 | ||
| 
						 | 
					5118f7b47c | ||
| 
						 | 
					1c1d7bda2c | ||
| 
						 | 
					bdae662c94 | ||
| 
						 | 
					0108d4e323 | ||
| 
						 | 
					4305793bad | ||
| 
						 | 
					d2d51eeff0 | ||
| 
						 | 
					3be42b28c1 | ||
| 
						 | 
					ee70ef8771 | ||
| 
						 | 
					5f9fe0f8d0 | ||
| 
						 | 
					7589acc9e8 | ||
| 
						 | 
					94f539bdac | ||
| 
						 | 
					e637fd2386 | ||
| 
						 | 
					6e785bee32 | ||
| 
						 | 
					f883e4f7b8 | ||
| 
						 | 
					5daa7bb7a4 | ||
| 
						 | 
					b0a84d0525 | ||
| 
						 | 
					f1f84ba223 | ||
| 
						 | 
					db830f26cb | ||
| 
						 | 
					61a606dade | ||
| 
						 | 
					2d95575edb | ||
| 
						 | 
					d707483ce3 | ||
| 
						 | 
					e2deb622c2 | ||
| 
						 | 
					6e792a557e | ||
| 
						 | 
					ea2138cf90 | ||
| 
						 | 
					992f3cb78e | ||
| 
						 | 
					828b2ff676 | ||
| 
						 | 
					a231a8272c | ||
| 
						 | 
					f2604b35dc | ||
| 
						 | 
					fc05630f1f | ||
| 
						 | 
					ad960ddbce | ||
| 
						 | 
					239a69680c | ||
| 
						 | 
					f4f1df70f2 | ||
| 
						 | 
					782e9e6554 | ||
| 
						 | 
					64de0113f1 | ||
| 
						 | 
					84db615abc | ||
| 
						 | 
					7c6a56cc63 | ||
| 
						 | 
					a20600b917 | ||
| 
						 | 
					4986fd4111 | ||
| 
						 | 
					96639424e2 | ||
| 
						 | 
					6ac733bf09 | ||
| 
						 | 
					25d82d3311 | ||
| 
						 | 
					f9800fe5a0 | ||
| 
						 | 
					542d991b4c | ||
| 
						 | 
					d1d6963eba | ||
| 
						 | 
					7058b807cd | ||
| 
						 | 
					f49d2561cb | ||
| 
						 | 
					a63e5f1971 | ||
| 
						 | 
					ebbc8a3d8e | ||
| 
						 | 
					08b2d3ba9a | ||
| 
						 | 
					72fbd9f97c | ||
| 
						 | 
					5b6d0419d9 | ||
| 
						 | 
					9df9eeeb18 | ||
| 
						 | 
					5b6321a237 | ||
| 
						 | 
					5e0c455842 | ||
| 
						 | 
					4d687b13cf | ||
| 
						 | 
					d7b8193716 | ||
| 
						 | 
					2e51813417 | ||
| 
						 | 
					90f445e1c9 | ||
| 
						 | 
					143d288cba | ||
| 
						 | 
					13a2ccc46f | ||
| 
						 | 
					ea2b7d7079 | ||
| 
						 | 
					0b52786ce1 | ||
| 
						 | 
					e36469149a | ||
| 
						 | 
					e5fc266be5 | ||
| 
						 | 
					3e4cd634cc | ||
| 
						 | 
					06976f82e7 | ||
| 
						 | 
					fe7c6c90a8 | ||
| 
						 | 
					960a4b537a | ||
| 
						 | 
					c756b1e762 | ||
| 
						 | 
					06921ec84f | ||
| 
						 | 
					8cb1cec656 | ||
| 
						 | 
					a46657d185 | ||
| 
						 | 
					28acf422cb | ||
| 
						 | 
					a7d5da8857 | ||
| 
						 | 
					931a548be3 | ||
| 
						 | 
					bcddbd0f6a | ||
| 
						 | 
					b3dfdb5a3b | ||
| 
						 | 
					6ccc51fd20 | ||
| 
						 | 
					0ea5709a32 | ||
| 
						 | 
					67a2698dac | ||
| 
						 | 
					eea4acfa5c | ||
| 
						 | 
					c99d32efe6 | ||
| 
						 | 
					9fa7591beb | ||
| 
						 | 
					066263f377 | ||
| 
						 | 
					20c1a35211 | ||
| 
						 | 
					ea6112b165 | ||
| 
						 | 
					e222100afe | 
							
								
								
									
										43
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -2,25 +2,14 @@ config-devices.*
 | 
			
		||||
config-all-devices.*
 | 
			
		||||
config-host.*
 | 
			
		||||
config-target.*
 | 
			
		||||
trace.h
 | 
			
		||||
trace.c
 | 
			
		||||
trace-dtrace.h
 | 
			
		||||
trace-dtrace.dtrace
 | 
			
		||||
*-timestamp
 | 
			
		||||
i386
 | 
			
		||||
*-softmmu
 | 
			
		||||
*-darwin-user
 | 
			
		||||
*-linux-user
 | 
			
		||||
*-bsd-user
 | 
			
		||||
libdis*
 | 
			
		||||
libhw32
 | 
			
		||||
libhw64
 | 
			
		||||
libuser
 | 
			
		||||
linux-headers/asm
 | 
			
		||||
qapi-generated
 | 
			
		||||
qapi-types.[ch]
 | 
			
		||||
qapi-visit.[ch]
 | 
			
		||||
qmp-commands.h
 | 
			
		||||
qmp-marshal.c
 | 
			
		||||
qemu-doc.html
 | 
			
		||||
qemu-tech.html
 | 
			
		||||
qemu-doc.info
 | 
			
		||||
@@ -33,22 +22,11 @@ qemu-img
 | 
			
		||||
qemu-nbd
 | 
			
		||||
qemu-nbd.8
 | 
			
		||||
qemu-nbd.pod
 | 
			
		||||
qemu-options.def
 | 
			
		||||
qemu-options.texi
 | 
			
		||||
qemu-img-cmds.texi
 | 
			
		||||
qemu-img-cmds.h
 | 
			
		||||
qemu-io
 | 
			
		||||
qemu-ga
 | 
			
		||||
qemu-bridge-helper
 | 
			
		||||
qemu-monitor.texi
 | 
			
		||||
QMP/qmp-commands.txt
 | 
			
		||||
test-coroutine
 | 
			
		||||
test-qmp-input-visitor
 | 
			
		||||
test-qmp-output-visitor
 | 
			
		||||
test-string-input-visitor
 | 
			
		||||
test-string-output-visitor
 | 
			
		||||
fsdev/virtfs-proxy-helper.1
 | 
			
		||||
fsdev/virtfs-proxy-helper.pod
 | 
			
		||||
.gdbinit
 | 
			
		||||
*.a
 | 
			
		||||
*.aux
 | 
			
		||||
@@ -58,34 +36,17 @@ fsdev/virtfs-proxy-helper.pod
 | 
			
		||||
*.fn
 | 
			
		||||
*.ky
 | 
			
		||||
*.log
 | 
			
		||||
*.pdf
 | 
			
		||||
*.cps
 | 
			
		||||
*.fns
 | 
			
		||||
*.kys
 | 
			
		||||
*.pg
 | 
			
		||||
*.pyc
 | 
			
		||||
*.toc
 | 
			
		||||
*.tp
 | 
			
		||||
*.vr
 | 
			
		||||
*.d
 | 
			
		||||
*.o
 | 
			
		||||
*.swp
 | 
			
		||||
*.orig
 | 
			
		||||
.pc
 | 
			
		||||
patches
 | 
			
		||||
pc-bios/bios-pq/status
 | 
			
		||||
pc-bios/vgabios-pq/status
 | 
			
		||||
pc-bios/optionrom/linuxboot.bin
 | 
			
		||||
pc-bios/optionrom/linuxboot.raw
 | 
			
		||||
pc-bios/optionrom/linuxboot.img
 | 
			
		||||
pc-bios/optionrom/multiboot.bin
 | 
			
		||||
pc-bios/optionrom/multiboot.raw
 | 
			
		||||
pc-bios/optionrom/multiboot.img
 | 
			
		||||
pc-bios/optionrom/kvmvapic.bin
 | 
			
		||||
pc-bios/optionrom/kvmvapic.raw
 | 
			
		||||
pc-bios/optionrom/kvmvapic.img
 | 
			
		||||
pc-bios/optionrom/extboot.bin
 | 
			
		||||
.stgit-*
 | 
			
		||||
cscope.*
 | 
			
		||||
tags
 | 
			
		||||
TAGS
 | 
			
		||||
*~
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -1,21 +1,6 @@
 | 
			
		||||
[submodule "roms/vgabios"]
 | 
			
		||||
	path = roms/vgabios
 | 
			
		||||
	url = git://git.qemu.org/vgabios.git/
 | 
			
		||||
	url = ../vgabios.git
 | 
			
		||||
[submodule "roms/seabios"]
 | 
			
		||||
	path = roms/seabios
 | 
			
		||||
	url = git://git.qemu.org/seabios.git/
 | 
			
		||||
[submodule "roms/SLOF"]
 | 
			
		||||
	path = roms/SLOF
 | 
			
		||||
	url = git://git.qemu.org/SLOF.git
 | 
			
		||||
[submodule "roms/ipxe"]
 | 
			
		||||
	path = roms/ipxe
 | 
			
		||||
	url = git://git.qemu.org/ipxe.git
 | 
			
		||||
[submodule "roms/openbios"]
 | 
			
		||||
	path = roms/openbios
 | 
			
		||||
	url = git://git.qemu.org/openbios.git
 | 
			
		||||
[submodule "roms/qemu-palcode"]
 | 
			
		||||
	path = roms/qemu-palcode
 | 
			
		||||
	url = git://repo.or.cz/qemu-palcode.git
 | 
			
		||||
[submodule "roms/sgabios"]
 | 
			
		||||
	path = roms/sgabios
 | 
			
		||||
	url = git://git.qemu.org/sgabios.git
 | 
			
		||||
	url = ../seabios.git
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								.mailmap
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								.mailmap
									
									
									
									
									
								
							@@ -1,16 +0,0 @@
 | 
			
		||||
# This mailmap just translates the weird addresses from the original import into git
 | 
			
		||||
# into proper addresses so that they are counted properly in git shortlog output.
 | 
			
		||||
#
 | 
			
		||||
Andrzej Zaborowski <balrogg@gmail.com> balrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
Anthony Liguori <aliguori@us.ibm.com> aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
Aurelien Jarno <aurelien@aurel32.net> aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
Blue Swirl <blauwirbel@gmail.com> blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
Edgar E. Iglesias <edgar.iglesias@gmail.com> edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
Fabrice Bellard <fabrice@bellard.org> bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
Jocelyn Mayer <l_indien@magic.fr> j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
Paul Brook <paul@codesourcery.com> pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
Thiemo Seufer <ths@networkno.de> ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
# There is also a:
 | 
			
		||||
#    (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
 | 
			
		||||
# for the cvs2svn initialization commit e63c3dc74bf.
 | 
			
		||||
							
								
								
									
										16
									
								
								CODING_STYLE
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								CODING_STYLE
									
									
									
									
									
								
							@@ -1,9 +1,6 @@
 | 
			
		||||
QEMU Coding Style
 | 
			
		||||
Qemu Coding Style
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
Please use the script checkpatch.pl in the scripts directory to check
 | 
			
		||||
patches before submitting.
 | 
			
		||||
 | 
			
		||||
1. Whitespace
 | 
			
		||||
 | 
			
		||||
Of course, the most important aspect in any coding style is whitespace.
 | 
			
		||||
@@ -44,14 +41,13 @@ Rationale:
 | 
			
		||||
3. Naming
 | 
			
		||||
 | 
			
		||||
Variables are lower_case_with_underscores; easy to type and read.  Structured
 | 
			
		||||
type names are in CamelCase; harder to type but standing out.  Enum type
 | 
			
		||||
names and function type names should also be in CamelCase.  Scalar type
 | 
			
		||||
type names are in CamelCase; harder to type but standing out.  Scalar type
 | 
			
		||||
names are lower_case_with_underscores_ending_with_a_t, like the POSIX
 | 
			
		||||
uint64_t and family.  Note that this last convention contradicts POSIX
 | 
			
		||||
and is therefore likely to be changed.
 | 
			
		||||
 | 
			
		||||
When wrapping standard library functions, use the prefix qemu_ to alert
 | 
			
		||||
readers that they are seeing a wrapped version; otherwise avoid this prefix.
 | 
			
		||||
Typedefs are used to eliminate the redundant 'struct' keyword.  It is the
 | 
			
		||||
QEMU coding style.
 | 
			
		||||
 | 
			
		||||
4. Block structure
 | 
			
		||||
 | 
			
		||||
@@ -69,10 +65,6 @@ keyword.  Example:
 | 
			
		||||
        printf("a was something else entirely.\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Note that 'else if' is considered a single statement; otherwise a long if/
 | 
			
		||||
else if/else if/.../else sequence would need an indent for every else
 | 
			
		||||
statement.
 | 
			
		||||
 | 
			
		||||
An exception is the opening brace for a function; for reasons of tradition
 | 
			
		||||
and clarity it comes on a line by itself:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										195
									
								
								Changelog
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								Changelog
									
									
									
									
									
								
							@@ -1,8 +1,189 @@
 | 
			
		||||
This file documents changes for QEMU releases 0.12 and earlier.
 | 
			
		||||
For changelog information for later releases, see
 | 
			
		||||
http://wiki.qemu.org/ChangeLog or look at the git history for
 | 
			
		||||
more detailed information.
 | 
			
		||||
version 0.12.5
 | 
			
		||||
 - audio/alsa: Handle SND_PCM_STATE_SETUP in alsa_poll_handler
 | 
			
		||||
 - block: Handle multiwrite errors only when all requests have completed
 | 
			
		||||
 - block: Fix early failure in multiwrite
 | 
			
		||||
 - vpc: Use bdrv_(p)write_sync for metadata writes
 | 
			
		||||
 - vmdk: Use bdrv_(p)write_sync for metadata writes
 | 
			
		||||
 - qcow2: Use bdrv_(p)write_sync for metadata writes
 | 
			
		||||
 - qcow: Use bdrv_(p)write_sync for metadata writes
 | 
			
		||||
 - block: Add bdrv_(p)write_sync
 | 
			
		||||
 - qcow2: Restore L1 entry on l2_allocate failure
 | 
			
		||||
 - block/vdi: Fix image opening and creation for odd disk sizes
 | 
			
		||||
 - block/vpc: Fix conversion from size to disk geometry
 | 
			
		||||
 - qcow2: Remove abort on free_clusters failure
 | 
			
		||||
 - vmdk: Fix COW
 | 
			
		||||
 - qcow2: Fix creation of large images
 | 
			
		||||
 - vmdk: fix double free
 | 
			
		||||
 - qemu-options: add documentation for stdio signal=on|off
 | 
			
		||||
 - target-arm : fix parallel saturated subtraction implementation
 | 
			
		||||
 - target-arm : fix thumb2 parallel add/sub opcode decoding
 | 
			
		||||
 - target-arm: fix addsub/subadd implementation
 | 
			
		||||
 - target-i386: fix xchg rax,r8
 | 
			
		||||
 - block/vvfat.c: fix warnings with _FORTIFY_SOURCE
 | 
			
		||||
 - audio/alsa: Spelling typo (paramters)
 | 
			
		||||
 - target-mips: fix DINSU instruction
 | 
			
		||||
 - Correct definitions for FD_CMD_SAVE and FD_CMD_RESTORE
 | 
			
		||||
 - qcow2: Fix corruption after error in update_refcount
 | 
			
		||||
 - qcow2: Fix corruption after refblock allocation
 | 
			
		||||
 - block: Fix multiwrite with overlapping requests
 | 
			
		||||
 - qcow2: Fix error handling in l2_allocate
 | 
			
		||||
 - qcow2: Clear L2 table cache after write error
 | 
			
		||||
 - ide: Fix ide_dma_cancel
 | 
			
		||||
 - usb-bus: fix no params
 | 
			
		||||
 - Avoid crash on '-usbdevice <device>' without parameters
 | 
			
		||||
 - Fix -usbdevice crash
 | 
			
		||||
 - Fix multiboot compilation
 | 
			
		||||
 - Fix missing symbols in .rel/.rela.plt sections
 | 
			
		||||
 - target-ppc: fix RFI by clearing some bits of MSR
 | 
			
		||||
 - Fix typo in balloon help
 | 
			
		||||
 - arm_timer: fix oneshot mode
 | 
			
		||||
 - arm_timer: reload timer when enabled
 | 
			
		||||
 - qemu-sockets: avoid strlen of NULL pointer
 | 
			
		||||
 - block: fix aio_flush segfaults for read-only protocols (e.g. curl)
 | 
			
		||||
 - virtio-blk: fix barrier support
 | 
			
		||||
 - block: fix sector comparism in multiwrite_req_compare
 | 
			
		||||
 - pci: irq_state vmstate breakage
 | 
			
		||||
 - qemu-img: use the heap instead of the huge stack array for win32
 | 
			
		||||
 | 
			
		||||
version 0.12.4
 | 
			
		||||
 - Workaround for broken OSS_GETVERSION on FreeBSD, part two (Juergen Lock)
 | 
			
		||||
 - oss: fix fragment setting (malc)
 | 
			
		||||
 - oss: issue OSS_GETVERSION ioctl only when needed (malc)
 | 
			
		||||
 - oss: refactor code around policy setting (malc)
 | 
			
		||||
 - oss: workaround for cases when OSS_GETVERSION is not defined (malc)
 | 
			
		||||
 - block: Free iovec arrays allocated by multiwrite_merge() (Stefan Hajnoczi)
 | 
			
		||||
 - lsi: fix segfault in lsi_command_complete (Gerd Hoffmann)
 | 
			
		||||
 - lsi: pass lsi_request to lsi_reselect (Gerd Hoffmann)
 | 
			
		||||
 - lsi: move dma_len+dma_buf into lsi_request (Gerd Hoffmann)
 | 
			
		||||
 - lsi: move current_dev into lsi_request (Gerd Hoffmann)
 | 
			
		||||
 - lsi: have lsi_request for the whole life time of the request. (Gerd Hoffmann)
 | 
			
		||||
 - lsi: use QTAILQ for lsi_queue (Gerd Hoffmann)
 | 
			
		||||
 - tcp/mips: Change TCG_AREG0 (fp -> s0) (Stefan Weil)
 | 
			
		||||
 - sh_pci: fix memory and I/O access (Aurelien Jarno)
 | 
			
		||||
 - Fix incoming migration with iothread (Marcelo Tosatti)
 | 
			
		||||
 - Fix SIGFPE for vnc display of width/height = 1 (Chris Webb)
 | 
			
		||||
 - net: remove broken net_set_boot_mask() boot device validation (Eduardo Habkost)
 | 
			
		||||
 - qcow2: Remove request from in-flight list after error (Kevin Wolf)
 | 
			
		||||
 - qcow2: Don't ignore immediate read/write failures (Kevin Wolf)
 | 
			
		||||
 - block: Fix multiwrite memory leak in error case (Kevin Wolf)
 | 
			
		||||
 - block: Fix error code in multiwrite for immediate failures (Kevin Wolf)
 | 
			
		||||
 - block: Fix multiwrite error handling (Kevin Wolf)
 | 
			
		||||
 - scsi-disk: fix buffer overflow (Gerd Hoffmann)
 | 
			
		||||
 - qcow2: Rewrite alloc_refcount_block/grow_refcount_table (Kevin Wolf)
 | 
			
		||||
 - qcow2: Factor next_refcount_table_size out (Kevin Wolf)
 | 
			
		||||
 - block: avoid creating too large iovecs in multiwrite_merge (Christoph Hellwig)
 | 
			
		||||
 - json-parser: Fix segfault on malformed input (Kevin Wolf)
 | 
			
		||||
 - linux-user: switch default ppc64 CPU to 970fx from 970 (Aurelien Jarno)
 | 
			
		||||
 - target-sh4: MMU: fix store queue addresses (Aurelien Jarno)
 | 
			
		||||
 - target-sh4: MMU: fix ITLB priviledge check (Aurelien Jarno)
 | 
			
		||||
 - target-sh4: MMU: fix mem_idx computation (Aurelien Jarno)
 | 
			
		||||
 - sh7750: handle MMUCR TI bit (Aurelien Jarno)
 | 
			
		||||
 - UHCI spurious interrut fix (Paul Brook)
 | 
			
		||||
 - tcg/mips: fix branch offset during retranslation (Aurelien Jarno)
 | 
			
		||||
 - tcg/arm: correctly save/restore registers in prologue/epilogue (Aurelien Jarno)
 | 
			
		||||
 - workaround for cmd646 bmdma register access while no dma is active (Igor V. Kovalenko)
 | 
			
		||||
 - Fix corner case in chardev udp: parameter (Jan Kiszka)
 | 
			
		||||
 - Don't set default monitor when there is a mux'ed one (Jan Kiszka)
 | 
			
		||||
 - spelling typo (compatibilty) in hw/fw_cfg.c (Vagrant Cascadian)
 | 
			
		||||
 - fdc: fix drive property handling. (Gerd Hoffmann)
 | 
			
		||||
 - target-i386: fix commit c22549204a6edc431e8e4358e61bd56386ff6957 (TeLeMan)
 | 
			
		||||
 - target-i386: fix SIB decoding with index = 4 (Aurelien Jarno)
 | 
			
		||||
 - Fix segfault with ram_size > 4095M without kvm (Ryan Harper)
 | 
			
		||||
 - target-i386: Fix long jumps/calls in long mode with REX.W set (malc)
 | 
			
		||||
 - target-i386: fix lddqu SSE instruction (Aurelien Jarno)
 | 
			
		||||
 - qemu-char.c: drop debug printfs from qemu_chr_parse_compat (Jan Kiszka)
 | 
			
		||||
 - fix undefined shifts by >32 (Paolo Bonzini)
 | 
			
		||||
 - Fix qemu -net user,hostfwd= example (Aurelien Jarno)
 | 
			
		||||
 | 
			
		||||
version 0.12.3
 | 
			
		||||
  - kvm: Fix eflags corruption in kvm mode (Jan Kiszka)
 | 
			
		||||
  - qcow2: Fix access after end of array (Kevin Wolf)
 | 
			
		||||
  - ide save/restore pio/atapi cmd transfer fields and io buffer (Marcelo Tosatti)
 | 
			
		||||
  - net: Monitor command set_link finds only VLAN clients, fix (Markus Armbruster)
 | 
			
		||||
  - net: info network shows only VLAN clients, fix (Markus Armbruster)
 | 
			
		||||
  - net: net_check_clients() checks only VLAN clients, fix (Markus Armbruster)
 | 
			
		||||
  - net: Fix bogus "Warning: vlan 0 with no nics" with -device (Markus Armbruster)
 | 
			
		||||
  - net: net_check_clients() runs too early to see -device, fix (Markus Armbruster)
 | 
			
		||||
  - net: Remove unused net_client_uninit() (Markus Armbruster)
 | 
			
		||||
  - don't dereference NULL after failed strdup (Jim Meyering)
 | 
			
		||||
  - virtio-net: fix network stall under load (Tom Lendacky)
 | 
			
		||||
  - json: fix PRId64 on Win32 (Roy Tam)
 | 
			
		||||
  - fix inet_parse typo (Marcelo Tosatti)
 | 
			
		||||
  - iothread: fix vcpu stop with smp tcg (Marcelo Tosatti)
 | 
			
		||||
  - segfault due to buffer overrun in usb-serial (David S. Ahern)
 | 
			
		||||
  - qcow2: Fix signedness bugs (Kevin Wolf)
 | 
			
		||||
  - Do not ignore error, if open file failed (-serial /dev/tty) (Evgeniy Dushistov)
 | 
			
		||||
  - pc-bios: update to newer version of (stable) seabios (Anthony Liguori)
 | 
			
		||||
  - target-mips: fix ROTR and DROTR by zero (Aurelien Jarno)
 | 
			
		||||
  - target-mips: fix CpU exception for coprocessor 0 (Nathan Froyd)
 | 
			
		||||
  - tcg/mips: fix crash in tcg_out_qemu_ld() (Aurelien Jarno)
 | 
			
		||||
  - target-mips: don't call cpu_loop_exit() from helper.c (Aurelien Jarno)
 | 
			
		||||
  - virtio-blk: Fix error cases which ignored rerror/werror (Kevin Wolf)
 | 
			
		||||
  - virtio-blk: Fix restart after read error (Kevin Wolf)
 | 
			
		||||
  - virtio_blk: Factor virtio_blk_handle_request out (Kevin Wolf)
 | 
			
		||||
  - cirrus: Properly re-register cirrus_linear_io_addr on vram unmap (Jan Kiszka)
 | 
			
		||||
  - qcow2: Don't ignore qcow2_alloc_clusters return value (Kevin Wolf)
 | 
			
		||||
  - qcow2: Don't ignore update_refcount return value (Kevin Wolf)
 | 
			
		||||
  - qcow2: Allow updating no refcounts (Kevin Wolf)
 | 
			
		||||
  - qcow2: Improve error handling in update_refcount (Kevin Wolf)
 | 
			
		||||
  - qcow2: Fix error handling in grow_refcount_table (Kevin Wolf)
 | 
			
		||||
  - block: Return original error codes in bdrv_pread/write (Kevin Wolf)
 | 
			
		||||
  - qcow2: Return 0/-errno in qcow2_alloc_cluster_offset (Kevin Wolf)
 | 
			
		||||
  - qcow2: Return 0/-errno in get_cluster_table (Kevin Wolf)
 | 
			
		||||
  - qcow2: Fix error handling in qcow_save_vmstate (Kevin Wolf)
 | 
			
		||||
  - qcow2: Fix error handling in qcow2_grow_l1_table (Kevin Wolf)
 | 
			
		||||
  - win32/sdl: Fix toggle full screen (Herve Poussineau)
 | 
			
		||||
  - win32: pair qemu_memalign() with qemu_vfree() (Herve Poussineau)
 | 
			
		||||
  - vnc_refresh: calling vnc_update_client might free vs (Stefano Stabellini)
 | 
			
		||||
  - Musicpal: Fix descriptor walk in eth_send (Jan Kiszka)
 | 
			
		||||
  - Musicpal: Fix wm8750 I2C address (Jan Kiszka)
 | 
			
		||||
  - fix savevm command without id or tag (Marcelo Tosatti)
 | 
			
		||||
  - reduce number of reinjects on ACK (Gleb Natapov)
 | 
			
		||||
  - QMP: Fix asynchronous events delivery (Luiz Capitulino)
 | 
			
		||||
  - Documentation: Add missing documentation for qdev related command line options (Stefan Weil)
 | 
			
		||||
  - pc: add driver version compat properties (Gerd Hoffmann)
 | 
			
		||||
  - scsi: device version property (Gerd Hoffmann)
 | 
			
		||||
  - ide: device version property (Gerd Hoffmann)
 | 
			
		||||
  - QMP: Emit asynchronous events on all QMP monitors (Adam Litke)
 | 
			
		||||
  - Fix QEMU_WARN_UNUSED_RESULT (Kevin Wolf)
 | 
			
		||||
 | 
			
		||||
version 0.12.2:
 | 
			
		||||
  - Qemu's internal TFTP server breaks lock-step-iness of TFTP (Milan Plzik)
 | 
			
		||||
  - osdep.c: Fix accept4 fallback (Kevin Wolf)
 | 
			
		||||
  - pc: add rombar to compat properties for pc-0.10 and pc-0.11 (Gerd Hoffmann)
 | 
			
		||||
  - pci: allow loading roms via fw_cfg. (Gerd Hoffmann)
 | 
			
		||||
  - roms: rework rom loading via fw (Gerd Hoffmann)
 | 
			
		||||
  - fw_cfg: rom loader tweaks. (Gerd Hoffmann)
 | 
			
		||||
  - roms: minor fixes and cleanups. (Gerd Hoffmann)
 | 
			
		||||
  - pc: add machine type for 0.12 (Gerd Hoffmann)
 | 
			
		||||
  - loader: more ignores for rom intended to be loaded by the bios (Aurelien Jarno)
 | 
			
		||||
  - vnc_refresh: return if vd->timer is NULL (Stefano Stabellini)
 | 
			
		||||
  - QMP: Don't free async event's 'data' (Luiz Capitulino)
 | 
			
		||||
  - Handle TFTP ERROR from client (Thomas Horsten)
 | 
			
		||||
  - dmg: fix ->open failure (Christoph Hellwig)
 | 
			
		||||
  - virtio-pci: thinko fix (Michael S. Tsirkin)
 | 
			
		||||
  - pc-bios: Update README (SeaBIOS) (Stefan Weil)
 | 
			
		||||
  - vmware_vga: Check cursor dimensions passed from guest to avoid buffer overflow (Roland Dreier)
 | 
			
		||||
  - remove pending exception on vcpu reset. (Gleb Natapov)
 | 
			
		||||
  - Fix CPU topology initialization (Jiri Denemark)
 | 
			
		||||
  - MCE: Fix bug of IA32_MCG_STATUS after system reset (Huang Ying)
 | 
			
		||||
  - linuxboot: fix gdt address calculation (Avi Kivity)
 | 
			
		||||
  - QMP: Drop wrong assert() (Luiz Capitulino)
 | 
			
		||||
  - vnc: Fix artifacts in hextile decoding (Anthony Liguori)
 | 
			
		||||
  - target-i386: Fix "call im" on x86_64 when executing 32-bit code (Aurelien Jarno)
 | 
			
		||||
  - Add missing newline at the end of options list (Michael Tokarev)
 | 
			
		||||
  - Don't load options roms intended to be loaded by the bios in qemu (Avi Kivity)
 | 
			
		||||
  - USB: Improve usbdevice error messages (Scott Tsai)
 | 
			
		||||
  - cpu-all.h: fix cpu_get_real_ticks() #ifdef (Aurelien Jarno)
 | 
			
		||||
  - alpha: fix compile (Blue Swirl)
 | 
			
		||||
  - user_only: compile everything with -fpie (Kirill A. Shutemov)
 | 
			
		||||
  - fdc/sparc32: don't hang on detection under OBP (Artyom Tarasenko)
 | 
			
		||||
  - scsi-disk: Inquiry with allocation length of CDB < 36 (v4) (Artyom Tarasenko)
 | 
			
		||||
  - e1000: fix init values for command register (Michael S. Tsirkin)
 | 
			
		||||
 | 
			
		||||
version 0.12.1:
 | 
			
		||||
  - loader: fix rom loading at address 0 (fixes target-arm) (Aurelien Jarno)
 | 
			
		||||
  - loader: fix rom_copy (fixes multiboot) (Kevin Wolf)
 | 
			
		||||
 | 
			
		||||
version 0.12.0:
 | 
			
		||||
 | 
			
		||||
@@ -78,7 +259,7 @@ version 0.10.2:
 | 
			
		||||
 | 
			
		||||
  - fix savevm/loadvm (Anthony Liguori)
 | 
			
		||||
  - live migration: fix dirty tracking windows (Glauber Costa)
 | 
			
		||||
  - live migration: improve error propagation (Glauber Costa)
 | 
			
		||||
  - live migration: improve error propogation (Glauber Costa)
 | 
			
		||||
  - qcow2: fix image creation for > ~2TB images (Chris Wright)
 | 
			
		||||
  - hotplug: fix error handling for if= parameter (Eduardo Habkost)
 | 
			
		||||
  - qcow2: fix data corruption (Nolan Leake)
 | 
			
		||||
@@ -386,7 +567,7 @@ version 0.5.3:
 | 
			
		||||
  - support of CD-ROM change
 | 
			
		||||
  - multiple network interface support
 | 
			
		||||
  - initial x86-64 host support (Gwenole Beauchesne)
 | 
			
		||||
  - lret to outer privilege fix (OS/2 install fix)
 | 
			
		||||
  - lret to outer priviledge fix (OS/2 install fix)
 | 
			
		||||
  - task switch fixes (SkyOS boot)
 | 
			
		||||
  - VM save/restore commands
 | 
			
		||||
  - new timer API
 | 
			
		||||
@@ -531,7 +712,7 @@ version 0.1.5:
 | 
			
		||||
 | 
			
		||||
 - ppc64 support + personality() patch (Rusty Russell)
 | 
			
		||||
 - first Alpha CPU patches (Falk Hueffner)
 | 
			
		||||
 - removed bfd.h dependency
 | 
			
		||||
 - removed bfd.h dependancy
 | 
			
		||||
 - fixed shrd, shld, idivl and divl on PowerPC.
 | 
			
		||||
 - fixed buggy glibc PowerPC rint() function (test-i386 passes now on PowerPC).
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								EXTERNAL_DEPENDENCIES
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								EXTERNAL_DEPENDENCIES
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
seabios 9fb3f4d950744e97cc655b7d7b523d8bf101e4a0
 | 
			
		||||
vgabios 6e62666cfc19e7fd45dd0d7c3ad62fd8d0b5f67a
 | 
			
		||||
							
								
								
									
										124
									
								
								HACKING
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								HACKING
									
									
									
									
									
								
							@@ -1,124 +0,0 @@
 | 
			
		||||
1. Preprocessor
 | 
			
		||||
 | 
			
		||||
For variadic macros, stick with this C99-like syntax:
 | 
			
		||||
 | 
			
		||||
#define DPRINTF(fmt, ...)                                       \
 | 
			
		||||
    do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0)
 | 
			
		||||
 | 
			
		||||
2. C types
 | 
			
		||||
 | 
			
		||||
It should be common sense to use the right type, but we have collected
 | 
			
		||||
a few useful guidelines here.
 | 
			
		||||
 | 
			
		||||
2.1. Scalars
 | 
			
		||||
 | 
			
		||||
If you're using "int" or "long", odds are good that there's a better type.
 | 
			
		||||
If a variable is counting something, it should be declared with an
 | 
			
		||||
unsigned type.
 | 
			
		||||
 | 
			
		||||
If it's host memory-size related, size_t should be a good choice (use
 | 
			
		||||
ssize_t only if required). Guest RAM memory offsets must use ram_addr_t,
 | 
			
		||||
but only for RAM, it may not cover whole guest address space.
 | 
			
		||||
 | 
			
		||||
If it's file-size related, use off_t.
 | 
			
		||||
If it's file-offset related (i.e., signed), use off_t.
 | 
			
		||||
If it's just counting small numbers use "unsigned int";
 | 
			
		||||
(on all but oddball embedded systems, you can assume that that
 | 
			
		||||
type is at least four bytes wide).
 | 
			
		||||
 | 
			
		||||
In the event that you require a specific width, use a standard type
 | 
			
		||||
like int32_t, uint32_t, uint64_t, etc.  The specific types are
 | 
			
		||||
mandatory for VMState fields.
 | 
			
		||||
 | 
			
		||||
Don't use Linux kernel internal types like u32, __u32 or __le32.
 | 
			
		||||
 | 
			
		||||
Use target_phys_addr_t for guest physical addresses except pcibus_t
 | 
			
		||||
for PCI addresses.  In addition, ram_addr_t is a QEMU internal address
 | 
			
		||||
space that maps guest RAM physical addresses into an intermediate
 | 
			
		||||
address space that can map to host virtual address spaces.  Generally
 | 
			
		||||
speaking, the size of guest memory can always fit into ram_addr_t but
 | 
			
		||||
it would not be correct to store an actual guest physical address in a
 | 
			
		||||
ram_addr_t.
 | 
			
		||||
 | 
			
		||||
Use target_ulong (or abi_ulong) for CPU virtual addresses, however
 | 
			
		||||
devices should not need to use target_ulong.
 | 
			
		||||
 | 
			
		||||
Of course, take all of the above with a grain of salt.  If you're about
 | 
			
		||||
to use some system interface that requires a type like size_t, pid_t or
 | 
			
		||||
off_t, use matching types for any corresponding variables.
 | 
			
		||||
 | 
			
		||||
Also, if you try to use e.g., "unsigned int" as a type, and that
 | 
			
		||||
conflicts with the signedness of a related variable, sometimes
 | 
			
		||||
it's best just to use the *wrong* type, if "pulling the thread"
 | 
			
		||||
and fixing all related variables would be too invasive.
 | 
			
		||||
 | 
			
		||||
Finally, while using descriptive types is important, be careful not to
 | 
			
		||||
go overboard.  If whatever you're doing causes warnings, or requires
 | 
			
		||||
casts, then reconsider or ask for help.
 | 
			
		||||
 | 
			
		||||
2.2. Pointers
 | 
			
		||||
 | 
			
		||||
Ensure that all of your pointers are "const-correct".
 | 
			
		||||
Unless a pointer is used to modify the pointed-to storage,
 | 
			
		||||
give it the "const" attribute.  That way, the reader knows
 | 
			
		||||
up-front that this is a read-only pointer.  Perhaps more
 | 
			
		||||
importantly, if we're diligent about this, when you see a non-const
 | 
			
		||||
pointer, you're guaranteed that it is used to modify the storage
 | 
			
		||||
it points to, or it is aliased to another pointer that is.
 | 
			
		||||
 | 
			
		||||
2.3. Typedefs
 | 
			
		||||
Typedefs are used to eliminate the redundant 'struct' keyword.
 | 
			
		||||
 | 
			
		||||
2.4. Reserved namespaces in C and POSIX
 | 
			
		||||
Underscore capital, double underscore, and underscore 't' suffixes should be
 | 
			
		||||
avoided.
 | 
			
		||||
 | 
			
		||||
3. Low level memory management
 | 
			
		||||
 | 
			
		||||
Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
 | 
			
		||||
APIs is not allowed in the QEMU codebase. Instead of these routines,
 | 
			
		||||
use the GLib memory allocation routines g_malloc/g_malloc0/g_new/
 | 
			
		||||
g_new0/g_realloc/g_free or QEMU's qemu_vmalloc/qemu_memalign/qemu_vfree
 | 
			
		||||
APIs.
 | 
			
		||||
 | 
			
		||||
Please note that g_malloc will exit on allocation failure, so there
 | 
			
		||||
is no need to test for failure (as you would have to with malloc).
 | 
			
		||||
Calling g_malloc with a zero size is valid and will return NULL.
 | 
			
		||||
 | 
			
		||||
Memory allocated by qemu_vmalloc or qemu_memalign must be freed with
 | 
			
		||||
qemu_vfree, since breaking this will cause problems on Win32 and user
 | 
			
		||||
emulators.
 | 
			
		||||
 | 
			
		||||
4. String manipulation
 | 
			
		||||
 | 
			
		||||
Do not use the strncpy function.  According to the man page, it does
 | 
			
		||||
*not* guarantee a NULL-terminated buffer, which makes it extremely dangerous
 | 
			
		||||
to use.  Instead, use functionally equivalent function:
 | 
			
		||||
void pstrcpy(char *buf, int buf_size, const char *str)
 | 
			
		||||
 | 
			
		||||
Don't use strcat because it can't check for buffer overflows, but:
 | 
			
		||||
char *pstrcat(char *buf, int buf_size, const char *s)
 | 
			
		||||
 | 
			
		||||
The same limitation exists with sprintf and vsprintf, so use snprintf and
 | 
			
		||||
vsnprintf.
 | 
			
		||||
 | 
			
		||||
QEMU provides other useful string functions:
 | 
			
		||||
int strstart(const char *str, const char *val, const char **ptr)
 | 
			
		||||
int stristart(const char *str, const char *val, const char **ptr)
 | 
			
		||||
int qemu_strnlen(const char *s, int max_len)
 | 
			
		||||
 | 
			
		||||
There are also replacement character processing macros for isxyz and toxyz,
 | 
			
		||||
so instead of e.g. isalnum you should use qemu_isalnum.
 | 
			
		||||
 | 
			
		||||
Because of the memory management rules, you must use g_strdup/g_strndup
 | 
			
		||||
instead of plain strdup/strndup.
 | 
			
		||||
 | 
			
		||||
5. Printf-style functions
 | 
			
		||||
 | 
			
		||||
Whenever you add a new printf-style function, i.e., one with a format
 | 
			
		||||
string argument and following "..." in its prototype, be sure to use
 | 
			
		||||
gcc's printf attribute directive in the prototype.
 | 
			
		||||
 | 
			
		||||
This makes it so gcc's -Wformat and -Wformat-security options can do
 | 
			
		||||
their jobs and cross-check format strings with the number and types
 | 
			
		||||
of arguments.
 | 
			
		||||
							
								
								
									
										1
									
								
								KVM_VERSION
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								KVM_VERSION
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
qemu-kvm-0.12.5
 | 
			
		||||
							
								
								
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							@@ -6,7 +6,9 @@ The following points clarify the QEMU license:
 | 
			
		||||
GNU General Public License. Hence each source file contains its own
 | 
			
		||||
licensing information.
 | 
			
		||||
 | 
			
		||||
Many hardware device emulation sources are released under the BSD license.
 | 
			
		||||
In particular, the QEMU virtual CPU core library (libqemu.a) is
 | 
			
		||||
released under the GNU Lesser General Public License. Many hardware
 | 
			
		||||
device emulation sources are released under the BSD license.
 | 
			
		||||
 | 
			
		||||
3) The Tiny Code Generator (TCG) is released under the BSD license
 | 
			
		||||
   (see license headers in files).
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										719
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										719
									
								
								MAINTAINERS
									
									
									
									
									
								
							@@ -1,657 +1,88 @@
 | 
			
		||||
QEMU Maintainers
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
The intention of this file is not to establish who owns what portions of the
 | 
			
		||||
code base, but to provide a set of names that developers can consult when they
 | 
			
		||||
have a question about a particular subset and also to provide a set of names
 | 
			
		||||
to be CC'd when submitting a patch to obtain appropriate review.
 | 
			
		||||
 | 
			
		||||
In general, if you have a question about inclusion of a patch, you should
 | 
			
		||||
consult qemu-devel and not any specific individual privately.
 | 
			
		||||
 | 
			
		||||
Descriptions of section entries:
 | 
			
		||||
 | 
			
		||||
	M: Mail patches to: FullName <address@domain>
 | 
			
		||||
	L: Mailing list that is relevant to this area
 | 
			
		||||
	W: Web-page with status/info
 | 
			
		||||
	Q: Patchwork web based patch tracking system site
 | 
			
		||||
	T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit.
 | 
			
		||||
	S: Status, one of the following:
 | 
			
		||||
	   Supported:	Someone is actually paid to look after this.
 | 
			
		||||
	   Maintained:	Someone actually looks after it.
 | 
			
		||||
	   Odd Fixes:	It has a maintainer but they don't have time to do
 | 
			
		||||
			much other than throw the odd patch in. See below.
 | 
			
		||||
	   Orphan:	No current maintainer [but maybe you could take the
 | 
			
		||||
			role as you write your new code].
 | 
			
		||||
	   Obsolete:	Old code. Something tagged obsolete generally means
 | 
			
		||||
			it has been replaced by a better system and you
 | 
			
		||||
			should be using that.
 | 
			
		||||
	F: Files and directories with wildcard patterns.
 | 
			
		||||
	   A trailing slash includes all files and subdirectory files.
 | 
			
		||||
	   F:	drivers/net/	all files in and below drivers/net
 | 
			
		||||
	   F:	drivers/net/*	all files in drivers/net, but not below
 | 
			
		||||
	   F:	*/net/*		all files in "any top level directory"/net
 | 
			
		||||
	   One pattern per line.  Multiple F: lines acceptable.
 | 
			
		||||
	X: Files and directories that are NOT maintained, same rules as F:
 | 
			
		||||
	   Files exclusions are tested before file matches.
 | 
			
		||||
	   Can be useful for excluding a specific subdirectory, for instance:
 | 
			
		||||
	   F:	net/
 | 
			
		||||
	   X:	net/ipv6/
 | 
			
		||||
	   matches all files in and below net excluding net/ipv6/
 | 
			
		||||
	K: Keyword perl extended regex pattern to match content in a
 | 
			
		||||
	   patch or file.  For instance:
 | 
			
		||||
	   K: of_get_profile
 | 
			
		||||
	      matches patches or files that contain "of_get_profile"
 | 
			
		||||
	   K: \b(printk|pr_(info|err))\b
 | 
			
		||||
	      matches patches or files that contain one or more of the words
 | 
			
		||||
	      printk, pr_info or pr_err
 | 
			
		||||
	   One regex pattern per line.  Multiple K: lines acceptable.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
General Project Administration
 | 
			
		||||
------------------------------
 | 
			
		||||
M: Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
 | 
			
		||||
Guest CPU cores (TCG):
 | 
			
		||||
----------------------
 | 
			
		||||
Alpha
 | 
			
		||||
M: Richard Henderson <rth@twiddle.net>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-alpha/
 | 
			
		||||
 | 
			
		||||
ARM
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
M: Peter Maydell <peter.maydell@linaro.org>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-arm/
 | 
			
		||||
 | 
			
		||||
CRIS
 | 
			
		||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-cris/
 | 
			
		||||
 | 
			
		||||
LM32
 | 
			
		||||
M: Michael Walle <michael@walle.cc>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-lm32/
 | 
			
		||||
 | 
			
		||||
M68K
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: target-m68k/
 | 
			
		||||
 | 
			
		||||
MicroBlaze
 | 
			
		||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-microblaze/
 | 
			
		||||
 | 
			
		||||
MIPS
 | 
			
		||||
M: Aurelien Jarno <aurelien@aurel32.net>
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: target-mips/
 | 
			
		||||
 | 
			
		||||
PowerPC
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
L: qemu-ppc@nongnu.org
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-ppc/
 | 
			
		||||
 | 
			
		||||
S390
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-s390x/
 | 
			
		||||
 | 
			
		||||
SH4
 | 
			
		||||
M: Aurelien Jarno <aurelien@aurel32.net>
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: target-sh4/
 | 
			
		||||
 | 
			
		||||
SPARC
 | 
			
		||||
M: Blue Swirl <blauwirbel@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-sparc/
 | 
			
		||||
 | 
			
		||||
UniCore32
 | 
			
		||||
M: Guan Xuetao <gxt@mprc.pku.edu.cn>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-unicore32/
 | 
			
		||||
 | 
			
		||||
X86
 | 
			
		||||
M: qemu-devel@nongnu.org
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: target-i386/
 | 
			
		||||
 | 
			
		||||
Xtensa
 | 
			
		||||
M: Max Filippov <jcmvbkbc@gmail.com>
 | 
			
		||||
W: http://wiki.osll.spb.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-xtensa/
 | 
			
		||||
 | 
			
		||||
Guest CPU Cores (KVM):
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
Overall
 | 
			
		||||
M: Avi Kivity <avi@redhat.com>
 | 
			
		||||
M: Marcelo Tosatti <mtosatti@redhat.com>
 | 
			
		||||
L: kvm@vger.kernel.org
 | 
			
		||||
S: Supported
 | 
			
		||||
F: kvm-*
 | 
			
		||||
F: */kvm.*
 | 
			
		||||
 | 
			
		||||
PPC
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-ppc/kvm.c
 | 
			
		||||
 | 
			
		||||
S390
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: target-s390x/kvm.c
 | 
			
		||||
 | 
			
		||||
X86
 | 
			
		||||
M: Avi Kivity <avi@redhat.com>
 | 
			
		||||
M: Marcelo Tosatti <mtosatti@redhat.com>
 | 
			
		||||
L: kvm@vger.kernel.org
 | 
			
		||||
S: Supported
 | 
			
		||||
F: target-i386/kvm.c
 | 
			
		||||
 | 
			
		||||
Guest CPU Cores (Xen):
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
X86
 | 
			
		||||
M: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
 | 
			
		||||
L: xen-devel@lists.xensource.com
 | 
			
		||||
S: Supported
 | 
			
		||||
F: xen-*
 | 
			
		||||
F: */xen*
 | 
			
		||||
 | 
			
		||||
Hosts:
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
LINUX
 | 
			
		||||
L: qemu-devel@nongnu.org
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: linux-*
 | 
			
		||||
F: linux-headers/
 | 
			
		||||
 | 
			
		||||
POSIX
 | 
			
		||||
L: qemu-devel@nongnu.org
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: *posix*
 | 
			
		||||
 | 
			
		||||
W32, W64
 | 
			
		||||
L: qemu-devel@nongnu.org
 | 
			
		||||
M: Stefan Weil <sw@weilnetz.de>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: *win32*
 | 
			
		||||
 | 
			
		||||
ARM Machines
 | 
			
		||||
------------
 | 
			
		||||
Exynos
 | 
			
		||||
M: Evgeny Voevodin <e.voevodin@samsung.com>
 | 
			
		||||
M: Maksim Kozlov <m.kozlov@samsung.com>
 | 
			
		||||
M: Igor Mitsyanko <i.mitsyanko@samsung.com>
 | 
			
		||||
M: Dmitry Solodkiy <d.solodkiy@samsung.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/exynos*
 | 
			
		||||
 | 
			
		||||
Calxeda Highbank
 | 
			
		||||
M: Mark Langsdorf <mark.langsdorf@calxeda.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/highbank.c
 | 
			
		||||
F: hw/xgmac.c
 | 
			
		||||
 | 
			
		||||
Gumstix
 | 
			
		||||
M: qemu-devel@nongnu.org
 | 
			
		||||
S: Orphan
 | 
			
		||||
F: hw/gumstix.c
 | 
			
		||||
 | 
			
		||||
Integrator CP
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
M: Peter Maydell <peter.maydell@linaro.org>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/integratorcp.c
 | 
			
		||||
 | 
			
		||||
Mainstone
 | 
			
		||||
M: qemu-devel@nongnu.org
 | 
			
		||||
S: Orphan
 | 
			
		||||
F: hw/mainstone.c
 | 
			
		||||
 | 
			
		||||
Musicpal
 | 
			
		||||
M: Jan Kiszka <jan.kiszka@web.de>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/musicpal.c
 | 
			
		||||
 | 
			
		||||
nSeries
 | 
			
		||||
M: Andrzej Zaborowski <balrogg@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/nseries.c
 | 
			
		||||
 | 
			
		||||
Palm
 | 
			
		||||
M: Andrzej Zaborowski <balrogg@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/palm.c
 | 
			
		||||
 | 
			
		||||
Real View
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
M: Peter Maydell <peter.maydell@linaro.org>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/realview*
 | 
			
		||||
 | 
			
		||||
Spitz
 | 
			
		||||
M: Andrzej Zaborowski <balrogg@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/spitz.c
 | 
			
		||||
 | 
			
		||||
Stellaris
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
M: Peter Maydell <peter.maydell@linaro.org>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/stellaris.c
 | 
			
		||||
 | 
			
		||||
Versatile PB
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
M: Peter Maydell <peter.maydell@linaro.org>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/versatilepb.c
 | 
			
		||||
 | 
			
		||||
Xilinx Zynq
 | 
			
		||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/xilinx_zynq.c
 | 
			
		||||
F: hw/zynq_slcr.c
 | 
			
		||||
F: hw/cadence_*
 | 
			
		||||
 | 
			
		||||
CRIS Machines
 | 
			
		||||
-------------
 | 
			
		||||
Axis Dev88
 | 
			
		||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/axis_dev88.c
 | 
			
		||||
 | 
			
		||||
etraxfs
 | 
			
		||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/etraxfs.c
 | 
			
		||||
 | 
			
		||||
LM32 Machines
 | 
			
		||||
-------------
 | 
			
		||||
EVR32 and uclinux BSP
 | 
			
		||||
M: Michael Walle <michael@walle.cc>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/lm32_boards.c
 | 
			
		||||
 | 
			
		||||
milkymist
 | 
			
		||||
M: Michael Walle <michael@walle.cc>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/milkymist.c
 | 
			
		||||
 | 
			
		||||
M68K Machines
 | 
			
		||||
-------------
 | 
			
		||||
an5206
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/an5206.c
 | 
			
		||||
 | 
			
		||||
dummy_m68k
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/dummy_m68k.c
 | 
			
		||||
 | 
			
		||||
mcf5208
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/mcf5208.c
 | 
			
		||||
 | 
			
		||||
MicroBlaze Machines
 | 
			
		||||
-------------------
 | 
			
		||||
petalogix_s3adsp1800
 | 
			
		||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/petalogix_s3adsp1800.c
 | 
			
		||||
 | 
			
		||||
MIPS Machines
 | 
			
		||||
-------------
 | 
			
		||||
Jazz
 | 
			
		||||
M: Hervé Poussineau <hpoussin@reactos.org>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/mips_jazz.c
 | 
			
		||||
 | 
			
		||||
Malta
 | 
			
		||||
M: Aurelien Jarno <aurelien@aurel32.net>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/mips_malta.c
 | 
			
		||||
 | 
			
		||||
Mipssim
 | 
			
		||||
M: qemu-devel@nongnu.org
 | 
			
		||||
S: Orphan
 | 
			
		||||
F: hw/mips_mipssim.c
 | 
			
		||||
 | 
			
		||||
R4000
 | 
			
		||||
M: Aurelien Jarno <aurelien@aurel32.net>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/mips_r4k.c
 | 
			
		||||
 | 
			
		||||
PowerPC Machines
 | 
			
		||||
Project leaders:
 | 
			
		||||
----------------
 | 
			
		||||
405
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
L: qemu-ppc@nongnu.org
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/ppc405_boards.c
 | 
			
		||||
 | 
			
		||||
New World
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
L: qemu-ppc@nongnu.org
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/ppc_newworld.c
 | 
			
		||||
F: hw/unin_pci.c
 | 
			
		||||
F: hw/dec_pci.[hc]
 | 
			
		||||
Fabrice Bellard
 | 
			
		||||
Paul Brook
 | 
			
		||||
 | 
			
		||||
Old World
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
L: qemu-ppc@nongnu.org
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/ppc_oldworld.c
 | 
			
		||||
F: hw/grackle_pci.c
 | 
			
		||||
 | 
			
		||||
PReP
 | 
			
		||||
M: Andreas Färber <andreas.faerber@web.de>
 | 
			
		||||
L: qemu-ppc@nongnu.org
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: hw/ppc_prep.c
 | 
			
		||||
F: hw/prep_pci.[hc]
 | 
			
		||||
 | 
			
		||||
SH4 Machines
 | 
			
		||||
------------
 | 
			
		||||
R2D
 | 
			
		||||
M: Magnus Damm <magnus.damm@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/r2d.c
 | 
			
		||||
 | 
			
		||||
Shix
 | 
			
		||||
M: Magnus Damm <magnus.damm@gmail.com>
 | 
			
		||||
S: Orphan
 | 
			
		||||
F: hw/shix.c
 | 
			
		||||
 | 
			
		||||
SPARC Machines
 | 
			
		||||
--------------
 | 
			
		||||
Sun4m
 | 
			
		||||
M: Blue Swirl <blauwirbel@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/sun4m.c
 | 
			
		||||
 | 
			
		||||
Sun4u
 | 
			
		||||
M: Blue Swirl <blauwirbel@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/sun4u.c
 | 
			
		||||
 | 
			
		||||
S390 Machines
 | 
			
		||||
-------------
 | 
			
		||||
S390 Virtio
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/s390-*.c
 | 
			
		||||
 | 
			
		||||
X86 Machines
 | 
			
		||||
------------
 | 
			
		||||
PC
 | 
			
		||||
M: Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/pc.[ch]
 | 
			
		||||
F: hw/pc_piix.c
 | 
			
		||||
 | 
			
		||||
Xtensa Machines
 | 
			
		||||
---------------
 | 
			
		||||
sim
 | 
			
		||||
M: Max Filippov <jcmvbkbc@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/xtensa_sim.c
 | 
			
		||||
 | 
			
		||||
Avnet LX60
 | 
			
		||||
M: Max Filippov <jcmvbkbc@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/xtensa_lx60.c
 | 
			
		||||
 | 
			
		||||
Devices
 | 
			
		||||
-------
 | 
			
		||||
IDE
 | 
			
		||||
M: Kevin Wolf <kwolf@redhat.com>
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: hw/ide/
 | 
			
		||||
 | 
			
		||||
OMAP
 | 
			
		||||
M: Peter Maydell <peter.maydell@linaro.org>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/omap*
 | 
			
		||||
 | 
			
		||||
PCI
 | 
			
		||||
M: Michael S. Tsirkin <mst@redhat.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/pci*
 | 
			
		||||
F: hw/piix*
 | 
			
		||||
 | 
			
		||||
SCSI
 | 
			
		||||
M: Paolo Bonzini <pbonzini@redhat.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/virtio-scsi.*
 | 
			
		||||
F: hw/scsi*
 | 
			
		||||
T: git git://github.com/bonzini/qemu.git scsi-next
 | 
			
		||||
 | 
			
		||||
LSI53C895A
 | 
			
		||||
M: Paul Brook <paul@codesourcery.com>
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: hw/lsi53c895a.c
 | 
			
		||||
 | 
			
		||||
USB
 | 
			
		||||
M: Gerd Hoffmann <kraxel@redhat.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: hw/usb*
 | 
			
		||||
 | 
			
		||||
vhost
 | 
			
		||||
M: Michael S. Tsirkin <mst@redhat.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/vhost*
 | 
			
		||||
 | 
			
		||||
virtio
 | 
			
		||||
M: Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/virtio*
 | 
			
		||||
 | 
			
		||||
virtio-9p
 | 
			
		||||
M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/9pfs/
 | 
			
		||||
F: fsdev/
 | 
			
		||||
T: git git://github.com/kvaneesh/QEMU.git
 | 
			
		||||
 | 
			
		||||
virtio-blk
 | 
			
		||||
M: Kevin Wolf <kwolf@redhat.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/virtio-blk*
 | 
			
		||||
 | 
			
		||||
virtio-serial
 | 
			
		||||
M: Amit Shah <amit.shah@redhat.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: hw/virtio-serial*
 | 
			
		||||
F: hw/virtio-console*
 | 
			
		||||
 | 
			
		||||
Subsystems
 | 
			
		||||
CPU cores:
 | 
			
		||||
----------
 | 
			
		||||
Audio
 | 
			
		||||
M: Vassili Karpov (malc) <av1474@comtv.ru>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: audio/
 | 
			
		||||
 | 
			
		||||
Block
 | 
			
		||||
M: Kevin Wolf <kwolf@redhat.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: block*
 | 
			
		||||
F: block/
 | 
			
		||||
x86                Fabrice Bellard
 | 
			
		||||
ARM                Paul Brook
 | 
			
		||||
SPARC              Blue Swirl
 | 
			
		||||
MIPS               Thiemo Seufer
 | 
			
		||||
PowerPC            ?
 | 
			
		||||
M68K               Paul Brook
 | 
			
		||||
SH4                ?
 | 
			
		||||
CRIS               Edgar E. Iglesias
 | 
			
		||||
Alpha              ?
 | 
			
		||||
MicroBlaze         Edgar E. Iglesias
 | 
			
		||||
S390               ?
 | 
			
		||||
 | 
			
		||||
Character Devices
 | 
			
		||||
M: Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: qemu-char.c
 | 
			
		||||
 | 
			
		||||
GDB stub
 | 
			
		||||
M: qemu-devel@nongnu.org
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: gdbstub*
 | 
			
		||||
F: gdb-xml/
 | 
			
		||||
 | 
			
		||||
SPICE
 | 
			
		||||
M: Gerd Hoffmann <kraxel@redhat.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: ui/qemu-spice.h
 | 
			
		||||
F: ui/spice-*.c
 | 
			
		||||
F: audio/spiceaudio.c
 | 
			
		||||
F: hw/qxl*
 | 
			
		||||
 | 
			
		||||
Graphics
 | 
			
		||||
M: Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: ui/
 | 
			
		||||
 | 
			
		||||
Cocoa graphics
 | 
			
		||||
M: Andreas Färber <andreas.faerber@web.de>
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: ui/cocoa.m
 | 
			
		||||
 | 
			
		||||
Main loop
 | 
			
		||||
M: Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: vl.c
 | 
			
		||||
 | 
			
		||||
Monitor (QMP/HMP)
 | 
			
		||||
M: Luiz Capitulino <lcapitulino@redhat.com>
 | 
			
		||||
M: Markus Armbruster <armbru@redhat.com>
 | 
			
		||||
S: Supported
 | 
			
		||||
F: monitor.c
 | 
			
		||||
 | 
			
		||||
Network device layer
 | 
			
		||||
M: Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
M: Mark McLoughlin <markmc@redhat.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: net/
 | 
			
		||||
 | 
			
		||||
Network Block Device (NBD)
 | 
			
		||||
M: Paolo Bonzini <pbonzini@redhat.com>
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: block/nbd.c
 | 
			
		||||
F: nbd.*
 | 
			
		||||
F: qemu-nbd.c
 | 
			
		||||
T: git git://github.com/bonzini/qemu.git nbd-next
 | 
			
		||||
 | 
			
		||||
SLIRP
 | 
			
		||||
M: Jan Kiszka <jan.kiszka@siemens.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: slirp/
 | 
			
		||||
T: git git://git.kiszka.org/qemu.git queues/slirp
 | 
			
		||||
 | 
			
		||||
Tracing
 | 
			
		||||
M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: trace/
 | 
			
		||||
F: scripts/tracetool.py
 | 
			
		||||
F: scripts/tracetool/
 | 
			
		||||
F: docs/tracing.txt
 | 
			
		||||
T: git git://github.com/stefanha/qemu.git tracing
 | 
			
		||||
 | 
			
		||||
Checkpatch
 | 
			
		||||
M: Blue Swirl <blauwirbel@gmail.com>
 | 
			
		||||
S: Odd Fixes
 | 
			
		||||
F: scripts/checkpatch.pl
 | 
			
		||||
 | 
			
		||||
Usermode Emulation
 | 
			
		||||
------------------
 | 
			
		||||
BSD user
 | 
			
		||||
M: Blue Swirl <blauwirbel@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: bsd-user/
 | 
			
		||||
 | 
			
		||||
Linux user
 | 
			
		||||
M: Riku Voipio <riku.voipio@iki.fi>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: linux-user/
 | 
			
		||||
 | 
			
		||||
Tiny Code Generator (TCG)
 | 
			
		||||
Machines (sorted by CPU):
 | 
			
		||||
-------------------------
 | 
			
		||||
Common code
 | 
			
		||||
M: qemu-devel@nongnu.org
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/
 | 
			
		||||
 | 
			
		||||
ARM target
 | 
			
		||||
M: Andrzej Zaborowski <balrogg@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/arm/
 | 
			
		||||
x86
 | 
			
		||||
  pc.c                    Fabrice Bellard (new maintainer needed)
 | 
			
		||||
ARM
 | 
			
		||||
  integratorcp.c          Paul Brook
 | 
			
		||||
  versatilepb.c           Paul Brook
 | 
			
		||||
  Real View               Paul Brook
 | 
			
		||||
  spitz.c                 Andrzej Zaborowski
 | 
			
		||||
  palm.c                  Andrzej Zaborowski
 | 
			
		||||
  nseries.c               Andrzej Zaborowski
 | 
			
		||||
  stellaris.c             Paul Brook
 | 
			
		||||
  gumstix.c               Thorsten Zitterell
 | 
			
		||||
  mainstone.c             Armin Kuster
 | 
			
		||||
  musicpal.c              Jan Kiszka
 | 
			
		||||
SPARC
 | 
			
		||||
  sun4u.c                 Blue Swirl
 | 
			
		||||
  sun4m.c                 Blue Swirl
 | 
			
		||||
MIPS
 | 
			
		||||
  mips_r4k.c              Aurelien Jarno
 | 
			
		||||
  mips_malta.c            Aurelien Jarno
 | 
			
		||||
  mips_jazz.c             Hervé Poussineau
 | 
			
		||||
  mips_mipssim.c          Thiemo Seufer
 | 
			
		||||
PowerPC
 | 
			
		||||
  ppc_prep.c              ?
 | 
			
		||||
  ppc_oldworld.c          Fabrice Bellard
 | 
			
		||||
  ppc_chrp.c              Fabrice Bellard
 | 
			
		||||
  ppc405_boards.c         ?
 | 
			
		||||
M86K
 | 
			
		||||
  mcf5208.c               Paul Brook
 | 
			
		||||
  an5206.c                Paul Brook
 | 
			
		||||
  dummy_m68k.c            Paul Brook
 | 
			
		||||
SH4
 | 
			
		||||
  shix.c                  ?
 | 
			
		||||
  r2d.c                   Magnus Damm
 | 
			
		||||
CRIS
 | 
			
		||||
  etraxfs.c               Edgar E. Iglesias
 | 
			
		||||
  axis_dev88.c            Edgar E. Iglesias
 | 
			
		||||
Alpha
 | 
			
		||||
MicroBlaze
 | 
			
		||||
  petalogix_s3adsp1800.c  Edgar E. Iglesias
 | 
			
		||||
S390
 | 
			
		||||
  s390-*.c                Alexander Graf
 | 
			
		||||
 | 
			
		||||
HPPA target
 | 
			
		||||
M: Richard Henderson <rth@twiddle.net>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/hppa/
 | 
			
		||||
Generic Subsystems:
 | 
			
		||||
-------------------  
 | 
			
		||||
 | 
			
		||||
i386 target
 | 
			
		||||
M: qemu-devel@nongnu.org
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/i386/
 | 
			
		||||
 | 
			
		||||
IA64 target
 | 
			
		||||
M: Aurelien Jarno <aurelien@aurel32.net>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/ia64/
 | 
			
		||||
 | 
			
		||||
MIPS target
 | 
			
		||||
M: Aurelien Jarno <aurelien@aurel32.net>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/mips/
 | 
			
		||||
 | 
			
		||||
PPC
 | 
			
		||||
M: Vassili Karpov (malc) <av1474@comtv.ru>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/ppc/
 | 
			
		||||
 | 
			
		||||
PPC64 target
 | 
			
		||||
M: Vassili Karpov (malc) <av1474@comtv.ru>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/ppc64/
 | 
			
		||||
 | 
			
		||||
S390 target
 | 
			
		||||
M: Alexander Graf <agraf@suse.de>
 | 
			
		||||
M: Richard Henderson <rth@twiddle.net>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/s390/
 | 
			
		||||
 | 
			
		||||
SPARC target
 | 
			
		||||
M: Blue Swirl <blauwirbel@gmail.com>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/sparc/
 | 
			
		||||
 | 
			
		||||
TCI target
 | 
			
		||||
M: Stefan Weil <sw@weilnetz.de>
 | 
			
		||||
S: Maintained
 | 
			
		||||
F: tcg/tci/
 | 
			
		||||
 | 
			
		||||
Stable branches
 | 
			
		||||
---------------
 | 
			
		||||
Stable 1.0
 | 
			
		||||
L: qemu-stable@nongnu.org
 | 
			
		||||
T: git git://git.qemu.org/qemu-stable-1.0.git
 | 
			
		||||
S: Orphan
 | 
			
		||||
 | 
			
		||||
Stable 0.15
 | 
			
		||||
L: qemu-stable@nongnu.org
 | 
			
		||||
T: git git://git.qemu.org/qemu-stable-0.15.git
 | 
			
		||||
S: Orphan
 | 
			
		||||
 | 
			
		||||
Stable 0.14
 | 
			
		||||
L: qemu-stable@nongnu.org
 | 
			
		||||
T: git git://git.qemu.org/qemu-stable-0.14.git
 | 
			
		||||
S: Orphan
 | 
			
		||||
 | 
			
		||||
Stable 0.10
 | 
			
		||||
L: qemu-stable@nongnu.org
 | 
			
		||||
T: git git://git.qemu.org/qemu-stable-0.10.git
 | 
			
		||||
S: Orphan
 | 
			
		||||
Dynamic translator        Fabrice Bellard
 | 
			
		||||
Main loop                 Fabrice Bellard (new maintainer needed)
 | 
			
		||||
TCG                       Fabrice Bellard
 | 
			
		||||
IDE device                ?
 | 
			
		||||
SCSI device               Paul Brook
 | 
			
		||||
PCI layer                 ?
 | 
			
		||||
USB layer                 ?
 | 
			
		||||
Block layer               ?
 | 
			
		||||
Graphic layer             ?
 | 
			
		||||
Audio device layer        Vassili Karpov (malc)
 | 
			
		||||
Character device layer    ?
 | 
			
		||||
Network device layer      ?
 | 
			
		||||
GDB stub                  ?
 | 
			
		||||
Linux user                ?
 | 
			
		||||
Darwin user               ?
 | 
			
		||||
SLIRP                     ?
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										508
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										508
									
								
								Makefile
									
									
									
									
									
								
							@@ -1,15 +1,14 @@
 | 
			
		||||
# Makefile for QEMU.
 | 
			
		||||
 | 
			
		||||
# Always point to the root of the build tree (needs GNU make).
 | 
			
		||||
BUILD_DIR=$(CURDIR)
 | 
			
		||||
# This needs to be defined before rules.mak
 | 
			
		||||
GENERATED_HEADERS = config-host.h
 | 
			
		||||
 | 
			
		||||
# All following code might depend on configuration variables
 | 
			
		||||
ifneq ($(wildcard config-host.mak),)
 | 
			
		||||
# Put the all: rule here so that config-host.mak can contain dependencies.
 | 
			
		||||
all: build-all
 | 
			
		||||
include config-host.mak
 | 
			
		||||
include $(SRC_PATH)/rules.mak
 | 
			
		||||
config-host.mak: $(SRC_PATH)/configure
 | 
			
		||||
config-host.mak: configure
 | 
			
		||||
	@echo $@ is out-of-date, running configure
 | 
			
		||||
	@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
 | 
			
		||||
else
 | 
			
		||||
@@ -18,63 +17,38 @@ config-host.mak:
 | 
			
		||||
	@exit 1
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
GENERATED_HEADERS = config-host.h trace.h qemu-options.def
 | 
			
		||||
ifeq ($(TRACE_BACKEND),dtrace)
 | 
			
		||||
GENERATED_HEADERS += trace-dtrace.h
 | 
			
		||||
endif
 | 
			
		||||
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
 | 
			
		||||
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c trace.c
 | 
			
		||||
 | 
			
		||||
# Don't try to regenerate Makefile or configure
 | 
			
		||||
# We don't generate any of them
 | 
			
		||||
Makefile: ;
 | 
			
		||||
configure: ;
 | 
			
		||||
 | 
			
		||||
.PHONY: all clean cscope distclean dvi html info install install-doc \
 | 
			
		||||
	pdf recurse-all speed tar tarbin test build-all
 | 
			
		||||
	recurse-all speed tar tarbin test build-all
 | 
			
		||||
 | 
			
		||||
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
 | 
			
		||||
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
 | 
			
		||||
 | 
			
		||||
LIBS+=-lz $(LIBS_TOOLS)
 | 
			
		||||
 | 
			
		||||
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
 | 
			
		||||
 | 
			
		||||
ifdef BUILD_DOCS
 | 
			
		||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
 | 
			
		||||
ifdef CONFIG_VIRTFS
 | 
			
		||||
DOCS+=fsdev/virtfs-proxy-helper.1
 | 
			
		||||
endif
 | 
			
		||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8
 | 
			
		||||
else
 | 
			
		||||
DOCS=
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
 | 
			
		||||
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
 | 
			
		||||
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
 | 
			
		||||
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
 | 
			
		||||
 | 
			
		||||
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
 | 
			
		||||
	$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
-include $(SUBDIR_DEVICES_MAK_DEP)
 | 
			
		||||
 | 
			
		||||
%/config-devices.mak: default-configs/%.mak
 | 
			
		||||
	$(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $@ $<, "  GEN   $@")
 | 
			
		||||
	@if test -f $@; then \
 | 
			
		||||
	  if cmp -s $@.old $@; then \
 | 
			
		||||
	    mv $@.tmp $@; \
 | 
			
		||||
	    cp -p $@ $@.old; \
 | 
			
		||||
	$(call quiet-command,cat $< > $@.tmp, "  GEN   $@")
 | 
			
		||||
	@if test -f $@ ; then \
 | 
			
		||||
	  echo "WARNING: $@ out of date." ;\
 | 
			
		||||
	  echo "Run \"make defconfig\" to regenerate." ; \
 | 
			
		||||
	  rm $@.tmp ; \
 | 
			
		||||
	 else \
 | 
			
		||||
	    if test -f $@.old; then \
 | 
			
		||||
	      echo "WARNING: $@ (user modified) out of date.";\
 | 
			
		||||
	    else \
 | 
			
		||||
	      echo "WARNING: $@ out of date.";\
 | 
			
		||||
	    fi; \
 | 
			
		||||
	    echo "Run \"make defconfig\" to regenerate."; \
 | 
			
		||||
	    rm $@.tmp; \
 | 
			
		||||
	  fi; \
 | 
			
		||||
	 else \
 | 
			
		||||
	  mv $@.tmp $@; \
 | 
			
		||||
	  cp -p $@ $@.old; \
 | 
			
		||||
	  mv $@.tmp $@ ; \
 | 
			
		||||
	 fi
 | 
			
		||||
 | 
			
		||||
defconfig:
 | 
			
		||||
@@ -82,28 +56,34 @@ defconfig:
 | 
			
		||||
 | 
			
		||||
-include config-all-devices.mak
 | 
			
		||||
 | 
			
		||||
build-all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
 | 
			
		||||
build-all: $(DOCS) $(TOOLS) recurse-all
 | 
			
		||||
 | 
			
		||||
config-host.h: config-host.h-timestamp
 | 
			
		||||
config-host.h-timestamp: config-host.mak
 | 
			
		||||
qemu-options.def: $(SRC_PATH)/qemu-options.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
 | 
			
		||||
 | 
			
		||||
ifeq ($(KVM_KMOD),yes)
 | 
			
		||||
 | 
			
		||||
.PHONEY: kvm-kmod
 | 
			
		||||
 | 
			
		||||
all: kvm-kmod
 | 
			
		||||
 | 
			
		||||
kvm-kmod:
 | 
			
		||||
	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C kvm/kernel V="$(V)" )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
subdir-%: $(GENERATED_HEADERS)
 | 
			
		||||
	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
 | 
			
		||||
 | 
			
		||||
ifneq ($(wildcard config-host.mak),)
 | 
			
		||||
include $(SRC_PATH)/Makefile.objs
 | 
			
		||||
endif
 | 
			
		||||
$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
 | 
			
		||||
 | 
			
		||||
$(universal-obj-y) $(common-obj-y): $(GENERATED_HEADERS)
 | 
			
		||||
subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o
 | 
			
		||||
$(filter %-user,$(SUBDIR_RULES)): libuser.a
 | 
			
		||||
 | 
			
		||||
$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) subdir-libdis
 | 
			
		||||
 | 
			
		||||
$(filter %-user,$(SUBDIR_RULES)): $(GENERATED_HEADERS) $(universal-obj-y) $(trace-obj-y) subdir-libdis-user subdir-libuser
 | 
			
		||||
libuser.a: $(GENERATED_HEADERS)
 | 
			
		||||
	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libuser V="$(V)" TARGET_DIR="libuser/" all,)
 | 
			
		||||
 | 
			
		||||
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
 | 
			
		||||
romsubdir-%:
 | 
			
		||||
@@ -113,137 +93,194 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
 | 
			
		||||
 | 
			
		||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# QObject
 | 
			
		||||
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
 | 
			
		||||
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
 | 
			
		||||
qobject-obj-y += qerror.o
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# block-obj-y is code used by both qemu system emulation and qemu-img
 | 
			
		||||
 | 
			
		||||
block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
 | 
			
		||||
block-obj-y += nbd.o block.o aio.o aes.o osdep.o
 | 
			
		||||
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 | 
			
		||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 | 
			
		||||
block-obj-$(CONFIG_POSIX) += compatfd.o
 | 
			
		||||
 | 
			
		||||
block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 | 
			
		||||
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
 | 
			
		||||
block-nested-y += parallels.o nbd.o
 | 
			
		||||
block-nested-$(CONFIG_WIN32) += raw-win32.o
 | 
			
		||||
block-nested-$(CONFIG_POSIX) += raw-posix.o
 | 
			
		||||
block-nested-$(CONFIG_CURL) += curl.o
 | 
			
		||||
 | 
			
		||||
block-obj-y +=  $(addprefix block/, $(block-nested-y))
 | 
			
		||||
 | 
			
		||||
net-obj-y = net.o
 | 
			
		||||
net-nested-y = queue.o checksum.o util.o
 | 
			
		||||
net-nested-y += socket.o
 | 
			
		||||
net-nested-y += dump.o
 | 
			
		||||
net-nested-$(CONFIG_POSIX) += tap.o
 | 
			
		||||
net-nested-$(CONFIG_LINUX) += tap-linux.o
 | 
			
		||||
net-nested-$(CONFIG_WIN32) += tap-win32.o
 | 
			
		||||
net-nested-$(CONFIG_BSD) += tap-bsd.o
 | 
			
		||||
net-nested-$(CONFIG_SOLARIS) += tap-solaris.o
 | 
			
		||||
net-nested-$(CONFIG_AIX) += tap-aix.o
 | 
			
		||||
net-nested-$(CONFIG_SLIRP) += slirp.o
 | 
			
		||||
net-nested-$(CONFIG_VDE) += vde.o
 | 
			
		||||
net-obj-y += $(addprefix net/, $(net-nested-y))
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# libqemu_common.a: Target independent part of system emulation. The
 | 
			
		||||
# long term path is to suppress *all* target specific code in case of
 | 
			
		||||
# system emulation, i.e. a single QEMU executable should support all
 | 
			
		||||
# CPUs and machines.
 | 
			
		||||
 | 
			
		||||
obj-y = $(block-obj-y)
 | 
			
		||||
obj-y += $(net-obj-y)
 | 
			
		||||
obj-y += $(qobject-obj-y)
 | 
			
		||||
obj-y += readline.o console.o
 | 
			
		||||
 | 
			
		||||
obj-y += tcg-runtime.o host-utils.o
 | 
			
		||||
obj-y += irq.o ioport.o
 | 
			
		||||
obj-$(CONFIG_PTIMER) += ptimer.o
 | 
			
		||||
obj-$(CONFIG_MAX7310) += max7310.o
 | 
			
		||||
obj-$(CONFIG_WM8750) += wm8750.o
 | 
			
		||||
obj-$(CONFIG_TWL92230) += twl92230.o
 | 
			
		||||
obj-$(CONFIG_TSC2005) += tsc2005.o
 | 
			
		||||
obj-$(CONFIG_LM832X) += lm832x.o
 | 
			
		||||
obj-$(CONFIG_TMP105) += tmp105.o
 | 
			
		||||
obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
 | 
			
		||||
obj-$(CONFIG_SSD0303) += ssd0303.o
 | 
			
		||||
obj-$(CONFIG_SSD0323) += ssd0323.o
 | 
			
		||||
obj-$(CONFIG_ADS7846) += ads7846.o
 | 
			
		||||
obj-$(CONFIG_MAX111X) += max111x.o
 | 
			
		||||
obj-$(CONFIG_DS1338) += ds1338.o
 | 
			
		||||
obj-y += i2c.o smbus.o smbus_eeprom.o
 | 
			
		||||
obj-y += eeprom93xx.o
 | 
			
		||||
obj-y += scsi-disk.o cdrom.o
 | 
			
		||||
obj-y += scsi-generic.o scsi-bus.o
 | 
			
		||||
obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
 | 
			
		||||
obj-y += usb-serial.o usb-net.o usb-bus.o
 | 
			
		||||
obj-$(CONFIG_SSI) += ssi.o
 | 
			
		||||
obj-$(CONFIG_SSI_SD) += ssi-sd.o
 | 
			
		||||
obj-$(CONFIG_SD) += sd.o
 | 
			
		||||
obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
 | 
			
		||||
obj-y += bt-hci-csr.o
 | 
			
		||||
obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
 | 
			
		||||
obj-y += qemu-char.o aio.o savevm.o
 | 
			
		||||
obj-y += msmouse.o ps2.o
 | 
			
		||||
obj-y += qdev.o qdev-properties.o
 | 
			
		||||
obj-y += qemu-config.o block-migration.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_BRLAPI) += baum.o
 | 
			
		||||
obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 | 
			
		||||
 | 
			
		||||
audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 | 
			
		||||
 | 
			
		||||
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 | 
			
		||||
audio-obj-$(CONFIG_SDL) += sdlaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_OSS) += ossaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_ALSA) += alsaaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_FMOD) += fmodaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_ESD) += esdaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_PA) += paaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
 | 
			
		||||
audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
 | 
			
		||||
audio-obj-y += wavcapture.o
 | 
			
		||||
obj-y += $(addprefix audio/, $(audio-obj-y))
 | 
			
		||||
 | 
			
		||||
obj-y += keymaps.o
 | 
			
		||||
obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
 | 
			
		||||
obj-$(CONFIG_CURSES) += curses.o
 | 
			
		||||
obj-y += vnc.o acl.o d3des.o
 | 
			
		||||
obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
 | 
			
		||||
obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 | 
			
		||||
obj-$(CONFIG_COCOA) += cocoa.o
 | 
			
		||||
obj-$(CONFIG_IOTHREAD) += qemu-thread.o
 | 
			
		||||
 | 
			
		||||
slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
 | 
			
		||||
slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
 | 
			
		||||
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
 | 
			
		||||
obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
 | 
			
		||||
 | 
			
		||||
# xen backend driver support
 | 
			
		||||
obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
 | 
			
		||||
obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS+=$(CURL_CFLAGS)
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS += -I$(SRC_PATH)/include
 | 
			
		||||
cocoa.o: cocoa.m
 | 
			
		||||
 | 
			
		||||
ui/cocoa.o: ui/cocoa.m
 | 
			
		||||
keymaps.o: keymaps.c keymaps.h
 | 
			
		||||
 | 
			
		||||
ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
 | 
			
		||||
sdl_zoom.o: sdl_zoom.c sdl_zoom.h sdl_zoom_template.h
 | 
			
		||||
 | 
			
		||||
ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 | 
			
		||||
sdl.o: sdl.c keymaps.h sdl_keysym.h sdl_zoom.h
 | 
			
		||||
 | 
			
		||||
sdl.o audio/sdlaudio.o sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
 | 
			
		||||
 | 
			
		||||
acl.o: acl.h acl.c
 | 
			
		||||
 | 
			
		||||
vnc.h: vnc-tls.h vnc-auth-vencrypt.h vnc-auth-sasl.h keymaps.h
 | 
			
		||||
 | 
			
		||||
vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h acl.h
 | 
			
		||||
 | 
			
		||||
vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 | 
			
		||||
 | 
			
		||||
vnc-tls.o: vnc-tls.c vnc.h
 | 
			
		||||
 | 
			
		||||
vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h
 | 
			
		||||
 | 
			
		||||
vnc-auth-sasl.o: vnc-auth-sasl.c vnc.h
 | 
			
		||||
 | 
			
		||||
curses.o: curses.c keymaps.h curses_keys.h
 | 
			
		||||
 | 
			
		||||
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 | 
			
		||||
 | 
			
		||||
version.o: $(SRC_PATH)/version.rc config-host.h
 | 
			
		||||
	$(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
 | 
			
		||||
libqemu_common.a: $(obj-y)
 | 
			
		||||
 | 
			
		||||
version-obj-$(CONFIG_WIN32) += version.o
 | 
			
		||||
######################################################################
 | 
			
		||||
# Support building shared library libcacard
 | 
			
		||||
 | 
			
		||||
.PHONY: libcacard.la install-libcacard
 | 
			
		||||
ifeq ($(LIBTOOL),)
 | 
			
		||||
libcacard.la:
 | 
			
		||||
	@echo "libtool is missing, please install and rerun configure"; exit 1
 | 
			
		||||
 | 
			
		||||
install-libcacard:
 | 
			
		||||
	@echo "libtool is missing, please install and rerun configure"; exit 1
 | 
			
		||||
else
 | 
			
		||||
libcacard.la: $(GENERATED_HEADERS) $(oslib-obj-y) qemu-timer-common.o $(addsuffix .lo, $(basename $(trace-obj-y)))
 | 
			
		||||
	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,)
 | 
			
		||||
 | 
			
		||||
install-libcacard: libcacard.la
 | 
			
		||||
	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
 | 
			
		||||
endif
 | 
			
		||||
######################################################################
 | 
			
		||||
 | 
			
		||||
qemu-img.o: qemu-img-cmds.h
 | 
			
		||||
qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS)
 | 
			
		||||
 | 
			
		||||
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
 | 
			
		||||
	qemu-timer-common.o main-loop.o notify.o iohandler.o cutils.o async.o
 | 
			
		||||
tools-obj-$(CONFIG_POSIX) += compatfd.o
 | 
			
		||||
qemu-img$(EXESUF): qemu-img.o qemu-tool.o $(block-obj-y) $(qobject-obj-y)
 | 
			
		||||
 | 
			
		||||
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
 | 
			
		||||
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
 | 
			
		||||
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
 | 
			
		||||
qemu-nbd$(EXESUF):  qemu-nbd.o qemu-tool.o $(block-obj-y) $(qobject-obj-y)
 | 
			
		||||
 | 
			
		||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
 | 
			
		||||
qemu-bridge-helper.o: $(GENERATED_HEADERS)
 | 
			
		||||
 | 
			
		||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
 | 
			
		||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
 | 
			
		||||
qemu-io$(EXESUF):  qemu-io.o qemu-tool.o cmd.o $(block-obj-y) $(qobject-obj-y)
 | 
			
		||||
 | 
			
		||||
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $@")
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
$(qapi-obj-y): $(GENERATED_HEADERS)
 | 
			
		||||
qapi-dir := $(BUILD_DIR)/qapi-generated
 | 
			
		||||
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
 | 
			
		||||
qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
 | 
			
		||||
 | 
			
		||||
gen-out-type = $(subst .,-,$(suffix $@))
 | 
			
		||||
 | 
			
		||||
ifneq ($(wildcard config-host.mak),)
 | 
			
		||||
include $(SRC_PATH)/tests/Makefile
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
$(qapi-dir)/qga-qapi-types.c $(qapi-dir)/qga-qapi-types.h :\
 | 
			
		||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
 | 
			
		||||
$(qapi-dir)/qga-qapi-visit.c $(qapi-dir)/qga-qapi-visit.h :\
 | 
			
		||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
 | 
			
		||||
$(qapi-dir)/qga-qmp-commands.h $(qapi-dir)/qga-qmp-marshal.c :\
 | 
			
		||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
 | 
			
		||||
 | 
			
		||||
qapi-types.c qapi-types.h :\
 | 
			
		||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, "  GEN   $@")
 | 
			
		||||
qapi-visit.c qapi-visit.h :\
 | 
			
		||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
 | 
			
		||||
qmp-commands.h qmp-marshal.c :\
 | 
			
		||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, "  GEN   $@")
 | 
			
		||||
 | 
			
		||||
QGALIB_OBJ=$(addprefix $(qapi-dir)/, qga-qapi-types.o qga-qapi-visit.o qga-qmp-marshal.o)
 | 
			
		||||
QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
 | 
			
		||||
$(QGALIB_OBJ): $(QGALIB_GEN) $(GENERATED_HEADERS)
 | 
			
		||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) $(GENERATED_HEADERS)
 | 
			
		||||
 | 
			
		||||
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) $(QGALIB_OBJ)
 | 
			
		||||
 | 
			
		||||
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
 | 
			
		||||
check-qint: check-qint.o qint.o qemu-malloc.o
 | 
			
		||||
check-qstring: check-qstring.o qstring.o qemu-malloc.o
 | 
			
		||||
check-qdict: check-qdict.o qdict.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o
 | 
			
		||||
check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
 | 
			
		||||
check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o
 | 
			
		||||
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
# avoid old build problems by removing potentially incorrect old files
 | 
			
		||||
	rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
 | 
			
		||||
	rm -f qemu-options.def
 | 
			
		||||
	rm -f *.o *.d *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
 | 
			
		||||
	rm -Rf .libs
 | 
			
		||||
	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
 | 
			
		||||
	rm -f qom/*.o qom/*.d
 | 
			
		||||
	rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
 | 
			
		||||
	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d
 | 
			
		||||
	rm -f qemu-img-cmds.h
 | 
			
		||||
	rm -f trace/*.o trace/*.d
 | 
			
		||||
	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
 | 
			
		||||
	@# May not be present in GENERATED_HEADERS
 | 
			
		||||
	rm -f trace-dtrace.h trace-dtrace.h-timestamp
 | 
			
		||||
	rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp)
 | 
			
		||||
	rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp)
 | 
			
		||||
	rm -rf $(qapi-dir)
 | 
			
		||||
	$(MAKE) -C tests/tcg clean
 | 
			
		||||
	for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
 | 
			
		||||
	$(MAKE) -C tests clean
 | 
			
		||||
	for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser; do \
 | 
			
		||||
	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
 | 
			
		||||
	rm -f $$d/qemu-options.def; \
 | 
			
		||||
        done
 | 
			
		||||
 | 
			
		||||
distclean: clean
 | 
			
		||||
	rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
 | 
			
		||||
	rm -f config-all-devices.mak
 | 
			
		||||
	rm -f roms/seabios/config.mak roms/vgabios/config.mak
 | 
			
		||||
	rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
 | 
			
		||||
	rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
 | 
			
		||||
	rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
 | 
			
		||||
	rm -f qemu-doc.vr
 | 
			
		||||
	rm -f config.log
 | 
			
		||||
	rm -f linux-headers/asm
 | 
			
		||||
	rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
 | 
			
		||||
	for d in $(TARGET_DIRS) $(QEMULIBS); do \
 | 
			
		||||
	rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
 | 
			
		||||
	for d in $(TARGET_DIRS) libhw32 libhw64 libuser; do \
 | 
			
		||||
	rm -rf $$d || exit 1 ; \
 | 
			
		||||
        done
 | 
			
		||||
 | 
			
		||||
@@ -252,65 +289,59 @@ ar      de     en-us  fi  fr-be  hr     it  lv  nl         pl  ru     th \
 | 
			
		||||
common  de-ch  es     fo  fr-ca  hu     ja  mk  nl-be      pt  sl     tr
 | 
			
		||||
 | 
			
		||||
ifdef INSTALL_BLOBS
 | 
			
		||||
BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
 | 
			
		||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
 | 
			
		||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
 | 
			
		||||
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
 | 
			
		||||
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
 | 
			
		||||
qemu-icon.bmp \
 | 
			
		||||
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
 | 
			
		||||
mpc8544ds.dtb \
 | 
			
		||||
multiboot.bin linuxboot.bin kvmvapic.bin \
 | 
			
		||||
s390-zipl.rom \
 | 
			
		||||
spapr-rtas.bin slof.bin \
 | 
			
		||||
palcode-clipper
 | 
			
		||||
BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
 | 
			
		||||
video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
 | 
			
		||||
pxe-e1000.bin pxe-i82559er.bin \
 | 
			
		||||
pxe-ne2k_pci.bin pxe-pcnet.bin \
 | 
			
		||||
pxe-rtl8139.bin pxe-virtio.bin \
 | 
			
		||||
bamboo.dtb petalogix-s3adsp1800.dtb \
 | 
			
		||||
multiboot.bin linuxboot.bin
 | 
			
		||||
BLOBS += extboot.bin
 | 
			
		||||
BLOBS += vapic.bin
 | 
			
		||||
else
 | 
			
		||||
BLOBS=
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
install-doc: $(DOCS)
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
 | 
			
		||||
	$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(docdir)"
 | 
			
		||||
	$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(docdir)"
 | 
			
		||||
ifdef CONFIG_POSIX
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 | 
			
		||||
	$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
 | 
			
		||||
	$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
 | 
			
		||||
endif
 | 
			
		||||
ifdef CONFIG_VIRTFS
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 | 
			
		||||
	$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
 | 
			
		||||
endif
 | 
			
		||||
install-sysconfig:
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
 | 
			
		||||
	$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
 | 
			
		||||
 | 
			
		||||
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
 | 
			
		||||
install: all $(if $(BUILD_DOCS),install-doc)
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
 | 
			
		||||
ifneq ($(TOOLS),)
 | 
			
		||||
	$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
 | 
			
		||||
endif
 | 
			
		||||
ifneq ($(HELPERS-y),)
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
 | 
			
		||||
	$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
 | 
			
		||||
endif
 | 
			
		||||
ifneq ($(BLOBS),)
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
 | 
			
		||||
	set -e; for x in $(BLOBS); do \
 | 
			
		||||
		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
 | 
			
		||||
	    if [ -f $(SRC_PATH)/pc-bios/$$x ];then \
 | 
			
		||||
		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
 | 
			
		||||
	    fi \
 | 
			
		||||
	    ; if [ -f pc-bios/optionrom/$$x ];then \
 | 
			
		||||
		$(INSTALL_DATA) pc-bios/optionrom/$$x "$(DESTDIR)$(datadir)"; \
 | 
			
		||||
	    fi \
 | 
			
		||||
	done
 | 
			
		||||
endif
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
 | 
			
		||||
	set -e; for x in $(KEYMAPS); do \
 | 
			
		||||
		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
 | 
			
		||||
		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
 | 
			
		||||
	done
 | 
			
		||||
	for d in $(TARGET_DIRS); do \
 | 
			
		||||
	$(MAKE) -C $$d $@ || exit 1 ; \
 | 
			
		||||
        done
 | 
			
		||||
ifeq ($(KVM_KMOD),yes)
 | 
			
		||||
	$(MAKE) -C kvm/kernel $@
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# various test targets
 | 
			
		||||
test speed: all
 | 
			
		||||
	$(MAKE) -C tests/tcg $@
 | 
			
		||||
	$(MAKE) -C tests $@
 | 
			
		||||
 | 
			
		||||
.PHONY: TAGS
 | 
			
		||||
TAGS:
 | 
			
		||||
@@ -318,70 +349,53 @@ TAGS:
 | 
			
		||||
 | 
			
		||||
cscope:
 | 
			
		||||
	rm -f ./cscope.*
 | 
			
		||||
	find "$(SRC_PATH)" -name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
 | 
			
		||||
	find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files
 | 
			
		||||
	cscope -b
 | 
			
		||||
 | 
			
		||||
# documentation
 | 
			
		||||
MAKEINFO=makeinfo
 | 
			
		||||
MAKEINFOFLAGS=--no-headers --no-split --number-sections
 | 
			
		||||
TEXIFLAG=$(if $(V),,--quiet)
 | 
			
		||||
%.dvi: %.texi
 | 
			
		||||
	$(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
%.html: %.texi
 | 
			
		||||
	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \
 | 
			
		||||
	"  GEN   $@")
 | 
			
		||||
	$(call quiet-command,texi2html -I=. -monolithic -number $<,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
%.info: %.texi
 | 
			
		||||
	$(call quiet-command,$(MAKEINFO) $< -o $@,"  GEN   $@")
 | 
			
		||||
	$(call quiet-command,makeinfo -I . $< -o $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
%.pdf: %.texi
 | 
			
		||||
	$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<,"  GEN   $@")
 | 
			
		||||
%.dvi: %.texi
 | 
			
		||||
	$(call quiet-command,texi2dvi -I . $<,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
qemu-options.texi: $(SRC_PATH)/qemu-options.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@,"  GEN   $@")
 | 
			
		||||
qemu-monitor.texi: $(SRC_PATH)/qemu-monitor.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@,"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
 | 
			
		||||
	$(call quiet-command, \
 | 
			
		||||
	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
 | 
			
		||||
	  $(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
 | 
			
		||||
	  perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod && \
 | 
			
		||||
	  pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
 | 
			
		||||
	  "  GEN   $@")
 | 
			
		||||
 | 
			
		||||
qemu-img.1: qemu-img.texi qemu-img-cmds.texi
 | 
			
		||||
	$(call quiet-command, \
 | 
			
		||||
	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
 | 
			
		||||
	  $(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \
 | 
			
		||||
	  "  GEN   $@")
 | 
			
		||||
 | 
			
		||||
fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
 | 
			
		||||
	$(call quiet-command, \
 | 
			
		||||
	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \
 | 
			
		||||
	  $(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
 | 
			
		||||
	  perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod && \
 | 
			
		||||
	  pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
 | 
			
		||||
	  "  GEN   $@")
 | 
			
		||||
 | 
			
		||||
qemu-nbd.8: qemu-nbd.texi
 | 
			
		||||
	$(call quiet-command, \
 | 
			
		||||
	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
 | 
			
		||||
	  $(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
 | 
			
		||||
	  perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod && \
 | 
			
		||||
	  pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
 | 
			
		||||
	  "  GEN   $@")
 | 
			
		||||
 | 
			
		||||
dvi: qemu-doc.dvi qemu-tech.dvi
 | 
			
		||||
html: qemu-doc.html qemu-tech.html
 | 
			
		||||
info: qemu-doc.info qemu-tech.info
 | 
			
		||||
pdf: qemu-doc.pdf qemu-tech.pdf
 | 
			
		||||
 | 
			
		||||
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
 | 
			
		||||
	qemu-img.texi qemu-nbd.texi qemu-options.texi \
 | 
			
		||||
	qemu-monitor.texi qemu-img-cmds.texi
 | 
			
		||||
dvi: qemu-doc.dvi qemu-tech.dvi
 | 
			
		||||
 | 
			
		||||
html: qemu-doc.html qemu-tech.html
 | 
			
		||||
 | 
			
		||||
qemu-doc.dvi qemu-doc.html qemu-doc.info: qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-monitor.texi qemu-img-cmds.texi
 | 
			
		||||
 | 
			
		||||
VERSION ?= $(shell cat VERSION)
 | 
			
		||||
FILE = qemu-$(VERSION)
 | 
			
		||||
@@ -393,5 +407,63 @@ tar:
 | 
			
		||||
	cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn
 | 
			
		||||
	rm -rf /tmp/$(FILE)
 | 
			
		||||
 | 
			
		||||
# generate a binary distribution
 | 
			
		||||
tarbin:
 | 
			
		||||
	cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
 | 
			
		||||
	$(bindir)/qemu \
 | 
			
		||||
	$(bindir)/qemu-system-x86_64 \
 | 
			
		||||
	$(bindir)/qemu-system-arm \
 | 
			
		||||
	$(bindir)/qemu-system-cris \
 | 
			
		||||
	$(bindir)/qemu-system-m68k \
 | 
			
		||||
	$(bindir)/qemu-system-microblaze \
 | 
			
		||||
	$(bindir)/qemu-system-mips \
 | 
			
		||||
	$(bindir)/qemu-system-mipsel \
 | 
			
		||||
	$(bindir)/qemu-system-mips64 \
 | 
			
		||||
	$(bindir)/qemu-system-mips64el \
 | 
			
		||||
	$(bindir)/qemu-system-ppc \
 | 
			
		||||
	$(bindir)/qemu-system-ppcemb \
 | 
			
		||||
	$(bindir)/qemu-system-ppc64 \
 | 
			
		||||
	$(bindir)/qemu-system-sh4 \
 | 
			
		||||
	$(bindir)/qemu-system-sh4eb \
 | 
			
		||||
	$(bindir)/qemu-system-sparc \
 | 
			
		||||
	$(bindir)/qemu-i386 \
 | 
			
		||||
	$(bindir)/qemu-x86_64 \
 | 
			
		||||
	$(bindir)/qemu-alpha \
 | 
			
		||||
	$(bindir)/qemu-arm \
 | 
			
		||||
	$(bindir)/qemu-armeb \
 | 
			
		||||
	$(bindir)/qemu-cris \
 | 
			
		||||
	$(bindir)/qemu-m68k \
 | 
			
		||||
	$(bindir)/qemu-microblaze \
 | 
			
		||||
	$(bindir)/qemu-mips \
 | 
			
		||||
	$(bindir)/qemu-mipsel \
 | 
			
		||||
	$(bindir)/qemu-ppc \
 | 
			
		||||
	$(bindir)/qemu-ppc64 \
 | 
			
		||||
	$(bindir)/qemu-ppc64abi32 \
 | 
			
		||||
	$(bindir)/qemu-sh4 \
 | 
			
		||||
	$(bindir)/qemu-sh4eb \
 | 
			
		||||
	$(bindir)/qemu-sparc \
 | 
			
		||||
	$(bindir)/qemu-sparc64 \
 | 
			
		||||
	$(bindir)/qemu-sparc32plus \
 | 
			
		||||
	$(bindir)/qemu-img \
 | 
			
		||||
	$(bindir)/qemu-nbd \
 | 
			
		||||
	$(datadir)/bios.bin \
 | 
			
		||||
	$(datadir)/vgabios.bin \
 | 
			
		||||
	$(datadir)/vgabios-cirrus.bin \
 | 
			
		||||
	$(datadir)/ppc_rom.bin \
 | 
			
		||||
	$(datadir)/video.x \
 | 
			
		||||
	$(datadir)/openbios-sparc32 \
 | 
			
		||||
	$(datadir)/openbios-sparc64 \
 | 
			
		||||
	$(datadir)/openbios-ppc \
 | 
			
		||||
	$(datadir)/pxe-ne2k_pci.bin \
 | 
			
		||||
	$(datadir)/pxe-rtl8139.bin \
 | 
			
		||||
	$(datadir)/pxe-pcnet.bin \
 | 
			
		||||
	$(datadir)/pxe-e1000.bin \
 | 
			
		||||
	$(datadir)/extboot.bin \
 | 
			
		||||
	$(docdir)/qemu-doc.html \
 | 
			
		||||
	$(docdir)/qemu-tech.html \
 | 
			
		||||
	$(mandir)/man1/qemu.1 \
 | 
			
		||||
	$(mandir)/man1/qemu-img.1 \
 | 
			
		||||
	$(mandir)/man8/qemu-nbd.8
 | 
			
		||||
 | 
			
		||||
# Include automatically generated dependency files
 | 
			
		||||
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d)
 | 
			
		||||
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								Makefile.dis
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								Makefile.dis
									
									
									
									
									
								
							@@ -1,23 +0,0 @@
 | 
			
		||||
# Makefile for disassemblers.
 | 
			
		||||
 | 
			
		||||
include ../config-host.mak
 | 
			
		||||
include config.mak
 | 
			
		||||
include $(SRC_PATH)/rules.mak
 | 
			
		||||
 | 
			
		||||
.PHONY: all
 | 
			
		||||
 | 
			
		||||
$(call set-vpath, $(SRC_PATH))
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS+=-I..
 | 
			
		||||
 | 
			
		||||
include $(SRC_PATH)/Makefile.objs
 | 
			
		||||
 | 
			
		||||
all: $(libdis-y)
 | 
			
		||||
# Dummy command so that make thinks it has done something
 | 
			
		||||
	@true
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f *.o *.d *.a *~
 | 
			
		||||
 | 
			
		||||
# Include automatically generated dependency files
 | 
			
		||||
-include $(wildcard *.d */*.d)
 | 
			
		||||
							
								
								
									
										42
									
								
								Makefile.hw
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								Makefile.hw
									
									
									
									
									
								
							@@ -7,19 +7,49 @@ include $(SRC_PATH)/rules.mak
 | 
			
		||||
 | 
			
		||||
.PHONY: all
 | 
			
		||||
 | 
			
		||||
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
 | 
			
		||||
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS+=-I..
 | 
			
		||||
QEMU_CFLAGS += -I$(SRC_PATH)/include
 | 
			
		||||
QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
 | 
			
		||||
 | 
			
		||||
include $(SRC_PATH)/Makefile.objs
 | 
			
		||||
obj-y =
 | 
			
		||||
obj-y += loader.o
 | 
			
		||||
obj-y += virtio.o
 | 
			
		||||
obj-y += fw_cfg.o
 | 
			
		||||
obj-y += watchdog.o
 | 
			
		||||
obj-$(CONFIG_ECC) += ecc.o
 | 
			
		||||
obj-$(CONFIG_NAND) += nand.o
 | 
			
		||||
 | 
			
		||||
all: $(hw-obj-y)
 | 
			
		||||
obj-$(CONFIG_M48T59) += m48t59.o
 | 
			
		||||
obj-$(CONFIG_ESCC) += escc.o
 | 
			
		||||
 | 
			
		||||
# PCI watchdog devices
 | 
			
		||||
obj-y += wdt_i6300esb.o
 | 
			
		||||
 | 
			
		||||
# MSI-X depends on kvm for interrupt injection,
 | 
			
		||||
# so moved it from Makefile.hw to Makefile.target for now
 | 
			
		||||
# obj-y += msix.o
 | 
			
		||||
 | 
			
		||||
# PCI network cards
 | 
			
		||||
obj-y += ne2000.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_SMC91C111) += smc91c111.o
 | 
			
		||||
obj-$(CONFIG_LAN9118) += lan9118.o
 | 
			
		||||
 | 
			
		||||
# SCSI layer
 | 
			
		||||
obj-y += lsi53c895a.o
 | 
			
		||||
obj-$(CONFIG_ESP) += esp.o
 | 
			
		||||
 | 
			
		||||
obj-y += dma-helpers.o sysbus.o isa-bus.o
 | 
			
		||||
obj-$(CONFIG_QDEV_ADDR) += qdev-addr.o
 | 
			
		||||
 | 
			
		||||
all: $(HWLIB)
 | 
			
		||||
# Dummy command so that make thinks it has done something
 | 
			
		||||
	@true
 | 
			
		||||
 | 
			
		||||
$(HWLIB): $(obj-y)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~
 | 
			
		||||
	rm -f *.o *.d *.a *~
 | 
			
		||||
 | 
			
		||||
# Include automatically generated dependency files
 | 
			
		||||
-include $(wildcard *.d */*.d)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										475
									
								
								Makefile.objs
									
									
									
									
									
								
							
							
						
						
									
										475
									
								
								Makefile.objs
									
									
									
									
									
								
							@@ -1,475 +0,0 @@
 | 
			
		||||
#######################################################################
 | 
			
		||||
# Target-independent parts used in system and user emulation
 | 
			
		||||
universal-obj-y =
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# QObject
 | 
			
		||||
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
 | 
			
		||||
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
 | 
			
		||||
qobject-obj-y += qerror.o error.o qemu-error.o
 | 
			
		||||
 | 
			
		||||
universal-obj-y += $(qobject-obj-y)
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# QOM
 | 
			
		||||
include $(SRC_PATH)/qom/Makefile
 | 
			
		||||
qom-obj-y = $(addprefix qom/, $(qom-y))
 | 
			
		||||
qom-obj-twice-y = $(addprefix qom/, $(qom-twice-y))
 | 
			
		||||
 | 
			
		||||
universal-obj-y += $(qom-obj-y)
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# oslib-obj-y is code depending on the OS (win32 vs posix)
 | 
			
		||||
oslib-obj-y = osdep.o
 | 
			
		||||
oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
 | 
			
		||||
oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# coroutines
 | 
			
		||||
coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
 | 
			
		||||
coroutine-obj-y += qemu-coroutine-sleep.o
 | 
			
		||||
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
 | 
			
		||||
coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
 | 
			
		||||
else
 | 
			
		||||
ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
 | 
			
		||||
coroutine-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o
 | 
			
		||||
else
 | 
			
		||||
coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# block-obj-y is code used by both qemu system emulation and qemu-img
 | 
			
		||||
 | 
			
		||||
block-obj-y = cutils.o cache-utils.o qemu-option.o module.o async.o
 | 
			
		||||
block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
 | 
			
		||||
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
 | 
			
		||||
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 | 
			
		||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 | 
			
		||||
 | 
			
		||||
block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 | 
			
		||||
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
 | 
			
		||||
block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
 | 
			
		||||
block-nested-y += qed-check.o
 | 
			
		||||
block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 | 
			
		||||
block-nested-y += stream.o
 | 
			
		||||
block-nested-$(CONFIG_WIN32) += raw-win32.o
 | 
			
		||||
block-nested-$(CONFIG_POSIX) += raw-posix.o
 | 
			
		||||
block-nested-$(CONFIG_LIBISCSI) += iscsi.o
 | 
			
		||||
block-nested-$(CONFIG_CURL) += curl.o
 | 
			
		||||
block-nested-$(CONFIG_RBD) += rbd.o
 | 
			
		||||
 | 
			
		||||
block-obj-y +=  $(addprefix block/, $(block-nested-y))
 | 
			
		||||
 | 
			
		||||
net-obj-y = net.o
 | 
			
		||||
net-nested-y = queue.o checksum.o util.o
 | 
			
		||||
net-nested-y += socket.o
 | 
			
		||||
net-nested-y += dump.o
 | 
			
		||||
net-nested-$(CONFIG_POSIX) += tap.o
 | 
			
		||||
net-nested-$(CONFIG_LINUX) += tap-linux.o
 | 
			
		||||
net-nested-$(CONFIG_WIN32) += tap-win32.o
 | 
			
		||||
net-nested-$(CONFIG_BSD) += tap-bsd.o
 | 
			
		||||
net-nested-$(CONFIG_SOLARIS) += tap-solaris.o
 | 
			
		||||
net-nested-$(CONFIG_AIX) += tap-aix.o
 | 
			
		||||
net-nested-$(CONFIG_HAIKU) += tap-haiku.o
 | 
			
		||||
net-nested-$(CONFIG_SLIRP) += slirp.o
 | 
			
		||||
net-nested-$(CONFIG_VDE) += vde.o
 | 
			
		||||
net-obj-y += $(addprefix net/, $(net-nested-y))
 | 
			
		||||
 | 
			
		||||
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
 | 
			
		||||
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
 | 
			
		||||
# only pull in the actual virtio-9p device if we also enabled virtio.
 | 
			
		||||
CONFIG_REALLY_VIRTFS=y
 | 
			
		||||
fsdev-nested-y = qemu-fsdev.o virtio-9p-marshal.o
 | 
			
		||||
else
 | 
			
		||||
fsdev-nested-y = qemu-fsdev-dummy.o
 | 
			
		||||
endif
 | 
			
		||||
fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# Target independent part of system emulation. The long term path is to
 | 
			
		||||
# suppress *all* target specific code in case of system emulation, i.e. a
 | 
			
		||||
# single QEMU executable should support all CPUs and machines.
 | 
			
		||||
 | 
			
		||||
common-obj-y = $(block-obj-y) blockdev.o
 | 
			
		||||
common-obj-y += $(net-obj-y)
 | 
			
		||||
common-obj-y += $(qom-obj-twice-y)
 | 
			
		||||
common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
 | 
			
		||||
common-obj-y += readline.o console.o cursor.o
 | 
			
		||||
common-obj-y += $(oslib-obj-y)
 | 
			
		||||
common-obj-$(CONFIG_WIN32) += os-win32.o
 | 
			
		||||
common-obj-$(CONFIG_POSIX) += os-posix.o
 | 
			
		||||
 | 
			
		||||
common-obj-y += tcg-runtime.o host-utils.o main-loop.o
 | 
			
		||||
common-obj-y += irq.o input.o
 | 
			
		||||
common-obj-$(CONFIG_PTIMER) += ptimer.o
 | 
			
		||||
common-obj-$(CONFIG_MAX7310) += max7310.o
 | 
			
		||||
common-obj-$(CONFIG_WM8750) += wm8750.o
 | 
			
		||||
common-obj-$(CONFIG_TWL92230) += twl92230.o
 | 
			
		||||
common-obj-$(CONFIG_TSC2005) += tsc2005.o
 | 
			
		||||
common-obj-$(CONFIG_LM832X) += lm832x.o
 | 
			
		||||
common-obj-$(CONFIG_TMP105) += tmp105.o
 | 
			
		||||
common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
 | 
			
		||||
common-obj-$(CONFIG_SSD0303) += ssd0303.o
 | 
			
		||||
common-obj-$(CONFIG_SSD0323) += ssd0323.o
 | 
			
		||||
common-obj-$(CONFIG_ADS7846) += ads7846.o
 | 
			
		||||
common-obj-$(CONFIG_MAX111X) += max111x.o
 | 
			
		||||
common-obj-$(CONFIG_DS1338) += ds1338.o
 | 
			
		||||
common-obj-y += i2c.o smbus.o smbus_eeprom.o
 | 
			
		||||
common-obj-y += eeprom93xx.o
 | 
			
		||||
common-obj-y += scsi-disk.o cdrom.o
 | 
			
		||||
common-obj-y += scsi-generic.o scsi-bus.o
 | 
			
		||||
common-obj-y += hid.o
 | 
			
		||||
common-obj-y += usb/core.o usb/bus.o usb/desc.o usb/dev-hub.o
 | 
			
		||||
common-obj-y += usb/host-$(HOST_USB).o
 | 
			
		||||
common-obj-y += usb/dev-hid.o usb/dev-storage.o usb/dev-wacom.o
 | 
			
		||||
common-obj-y += usb/dev-serial.o usb/dev-network.o usb/dev-audio.o
 | 
			
		||||
common-obj-$(CONFIG_SSI) += ssi.o
 | 
			
		||||
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
 | 
			
		||||
common-obj-$(CONFIG_SD) += sd.o
 | 
			
		||||
common-obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o
 | 
			
		||||
common-obj-y += bt-hci-csr.o usb/dev-bluetooth.o
 | 
			
		||||
common-obj-y += buffered_file.o migration.o migration-tcp.o
 | 
			
		||||
common-obj-y += qemu-char.o #aio.o
 | 
			
		||||
common-obj-y += msmouse.o ps2.o
 | 
			
		||||
common-obj-y += qdev.o qdev-properties.o qdev-monitor.o
 | 
			
		||||
common-obj-y += block-migration.o iohandler.o
 | 
			
		||||
common-obj-y += pflib.o
 | 
			
		||||
common-obj-y += bitmap.o bitops.o
 | 
			
		||||
 | 
			
		||||
common-obj-$(CONFIG_BRLAPI) += baum.o
 | 
			
		||||
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 | 
			
		||||
common-obj-$(CONFIG_WIN32) += version.o
 | 
			
		||||
 | 
			
		||||
common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o spice-qemu-char.o
 | 
			
		||||
 | 
			
		||||
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 | 
			
		||||
audio-obj-$(CONFIG_SDL) += sdlaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_OSS) += ossaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_SPICE) += spiceaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_ALSA) += alsaaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_FMOD) += fmodaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_ESD) += esdaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_PA) += paaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
 | 
			
		||||
audio-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
 | 
			
		||||
audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
 | 
			
		||||
audio-obj-y += wavcapture.o
 | 
			
		||||
common-obj-y += $(addprefix audio/, $(audio-obj-y))
 | 
			
		||||
 | 
			
		||||
ui-obj-y += keymaps.o
 | 
			
		||||
ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
 | 
			
		||||
ui-obj-$(CONFIG_COCOA) += cocoa.o
 | 
			
		||||
ui-obj-$(CONFIG_CURSES) += curses.o
 | 
			
		||||
vnc-obj-y += vnc.o d3des.o
 | 
			
		||||
vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
 | 
			
		||||
vnc-obj-y += vnc-enc-tight.o vnc-palette.o
 | 
			
		||||
vnc-obj-y += vnc-enc-zrle.o
 | 
			
		||||
vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
 | 
			
		||||
vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 | 
			
		||||
ifdef CONFIG_VNC_THREAD
 | 
			
		||||
vnc-obj-y += vnc-jobs-async.o
 | 
			
		||||
else
 | 
			
		||||
vnc-obj-y += vnc-jobs-sync.o
 | 
			
		||||
endif
 | 
			
		||||
common-obj-y += $(addprefix ui/, $(ui-obj-y))
 | 
			
		||||
common-obj-$(CONFIG_VNC) += $(addprefix ui/, $(vnc-obj-y))
 | 
			
		||||
 | 
			
		||||
common-obj-y += iov.o acl.o
 | 
			
		||||
common-obj-$(CONFIG_POSIX) += compatfd.o
 | 
			
		||||
common-obj-y += notify.o event_notifier.o
 | 
			
		||||
common-obj-y += qemu-timer.o qemu-timer-common.o
 | 
			
		||||
 | 
			
		||||
slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
 | 
			
		||||
slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
 | 
			
		||||
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
 | 
			
		||||
common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
 | 
			
		||||
 | 
			
		||||
# xen backend driver support
 | 
			
		||||
common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
 | 
			
		||||
common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# libuser
 | 
			
		||||
 | 
			
		||||
user-obj-y =
 | 
			
		||||
user-obj-y += envlist.o path.o
 | 
			
		||||
user-obj-y += tcg-runtime.o host-utils.o
 | 
			
		||||
user-obj-y += cutils.o cache-utils.o
 | 
			
		||||
user-obj-y += module.o
 | 
			
		||||
user-obj-y += qemu-user.o
 | 
			
		||||
user-obj-y += $(trace-obj-y)
 | 
			
		||||
user-obj-y += $(qom-obj-twice-y)
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# libhw
 | 
			
		||||
 | 
			
		||||
hw-obj-y =
 | 
			
		||||
hw-obj-y += vl.o loader.o
 | 
			
		||||
hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
 | 
			
		||||
hw-obj-y += usb/libhw.o
 | 
			
		||||
hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 | 
			
		||||
hw-obj-y += fw_cfg.o
 | 
			
		||||
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o
 | 
			
		||||
hw-obj-$(CONFIG_PCI) += msix.o msi.o
 | 
			
		||||
hw-obj-$(CONFIG_PCI) += shpc.o
 | 
			
		||||
hw-obj-$(CONFIG_PCI) += slotid_cap.o
 | 
			
		||||
hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
 | 
			
		||||
hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
 | 
			
		||||
hw-obj-y += watchdog.o
 | 
			
		||||
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 | 
			
		||||
hw-obj-$(CONFIG_ECC) += ecc.o
 | 
			
		||||
hw-obj-$(CONFIG_NAND) += nand.o
 | 
			
		||||
hw-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
 | 
			
		||||
hw-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
 | 
			
		||||
 | 
			
		||||
hw-obj-$(CONFIG_M48T59) += m48t59.o
 | 
			
		||||
hw-obj-$(CONFIG_ESCC) += escc.o
 | 
			
		||||
hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
 | 
			
		||||
 | 
			
		||||
hw-obj-$(CONFIG_SERIAL) += serial.o
 | 
			
		||||
hw-obj-$(CONFIG_PARALLEL) += parallel.o
 | 
			
		||||
hw-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 | 
			
		||||
hw-obj-$(CONFIG_PCSPK) += pcspk.o
 | 
			
		||||
hw-obj-$(CONFIG_PCKBD) += pckbd.o
 | 
			
		||||
hw-obj-$(CONFIG_USB_UHCI) += usb/hcd-uhci.o
 | 
			
		||||
hw-obj-$(CONFIG_USB_OHCI) += usb/hcd-ohci.o
 | 
			
		||||
hw-obj-$(CONFIG_USB_EHCI) += usb/hcd-ehci.o
 | 
			
		||||
hw-obj-$(CONFIG_USB_XHCI) += usb/hcd-xhci.o
 | 
			
		||||
hw-obj-$(CONFIG_FDC) += fdc.o
 | 
			
		||||
hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
 | 
			
		||||
hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
 | 
			
		||||
hw-obj-$(CONFIG_DMA) += dma.o
 | 
			
		||||
hw-obj-$(CONFIG_I82374) += i82374.o
 | 
			
		||||
hw-obj-$(CONFIG_HPET) += hpet.o
 | 
			
		||||
hw-obj-$(CONFIG_APPLESMC) += applesmc.o
 | 
			
		||||
hw-obj-$(CONFIG_SMARTCARD) += usb/dev-smartcard-reader.o ccid-card-passthru.o
 | 
			
		||||
hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
 | 
			
		||||
hw-obj-$(CONFIG_USB_REDIR) += usb/redirect.o
 | 
			
		||||
hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
 | 
			
		||||
 | 
			
		||||
# PPC devices
 | 
			
		||||
hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
 | 
			
		||||
hw-obj-$(CONFIG_I82378) += i82378.o
 | 
			
		||||
# Mac shared devices
 | 
			
		||||
hw-obj-$(CONFIG_MACIO) += macio.o
 | 
			
		||||
hw-obj-$(CONFIG_CUDA) += cuda.o
 | 
			
		||||
hw-obj-$(CONFIG_ADB) += adb.o
 | 
			
		||||
hw-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
 | 
			
		||||
hw-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o
 | 
			
		||||
# OldWorld PowerMac
 | 
			
		||||
hw-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o
 | 
			
		||||
hw-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o
 | 
			
		||||
# NewWorld PowerMac
 | 
			
		||||
hw-obj-$(CONFIG_UNIN_PCI) += unin_pci.o
 | 
			
		||||
hw-obj-$(CONFIG_DEC_PCI) += dec_pci.o
 | 
			
		||||
# PowerPC E500 boards
 | 
			
		||||
hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
 | 
			
		||||
 | 
			
		||||
# MIPS devices
 | 
			
		||||
hw-obj-$(CONFIG_PIIX4) += piix4.o
 | 
			
		||||
hw-obj-$(CONFIG_G364FB) += g364fb.o
 | 
			
		||||
hw-obj-$(CONFIG_JAZZ_LED) += jazz_led.o
 | 
			
		||||
 | 
			
		||||
# PCI watchdog devices
 | 
			
		||||
hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
 | 
			
		||||
 | 
			
		||||
hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
 | 
			
		||||
 | 
			
		||||
# PCI network cards
 | 
			
		||||
hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
 | 
			
		||||
hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
 | 
			
		||||
hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
 | 
			
		||||
hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
 | 
			
		||||
hw-obj-$(CONFIG_E1000_PCI) += e1000.o
 | 
			
		||||
hw-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
 | 
			
		||||
 | 
			
		||||
hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
 | 
			
		||||
hw-obj-$(CONFIG_LAN9118) += lan9118.o
 | 
			
		||||
hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
 | 
			
		||||
hw-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
 | 
			
		||||
 | 
			
		||||
# IDE
 | 
			
		||||
hw-obj-$(CONFIG_IDE_CORE) += ide/core.o ide/atapi.o
 | 
			
		||||
hw-obj-$(CONFIG_IDE_QDEV) += ide/qdev.o
 | 
			
		||||
hw-obj-$(CONFIG_IDE_PCI) += ide/pci.o
 | 
			
		||||
hw-obj-$(CONFIG_IDE_ISA) += ide/isa.o
 | 
			
		||||
hw-obj-$(CONFIG_IDE_PIIX) += ide/piix.o
 | 
			
		||||
hw-obj-$(CONFIG_IDE_CMD646) += ide/cmd646.o
 | 
			
		||||
hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
 | 
			
		||||
hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
 | 
			
		||||
hw-obj-$(CONFIG_AHCI) += ide/ahci.o
 | 
			
		||||
hw-obj-$(CONFIG_AHCI) += ide/ich.o
 | 
			
		||||
 | 
			
		||||
# SCSI layer
 | 
			
		||||
hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
 | 
			
		||||
hw-obj-$(CONFIG_ESP) += esp.o
 | 
			
		||||
 | 
			
		||||
hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
 | 
			
		||||
hw-obj-y += qdev-addr.o
 | 
			
		||||
 | 
			
		||||
# VGA
 | 
			
		||||
hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
 | 
			
		||||
hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
 | 
			
		||||
hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
 | 
			
		||||
hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
 | 
			
		||||
hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
 | 
			
		||||
hw-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
 | 
			
		||||
 | 
			
		||||
hw-obj-$(CONFIG_RC4030) += rc4030.o
 | 
			
		||||
hw-obj-$(CONFIG_DP8393X) += dp8393x.o
 | 
			
		||||
hw-obj-$(CONFIG_DS1225Y) += ds1225y.o
 | 
			
		||||
hw-obj-$(CONFIG_MIPSNET) += mipsnet.o
 | 
			
		||||
 | 
			
		||||
hw-obj-y += qtest.o
 | 
			
		||||
 | 
			
		||||
# Sound
 | 
			
		||||
sound-obj-y =
 | 
			
		||||
sound-obj-$(CONFIG_SB16) += sb16.o
 | 
			
		||||
sound-obj-$(CONFIG_ES1370) += es1370.o
 | 
			
		||||
sound-obj-$(CONFIG_AC97) += ac97.o
 | 
			
		||||
sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
 | 
			
		||||
sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
 | 
			
		||||
sound-obj-$(CONFIG_CS4231A) += cs4231a.o
 | 
			
		||||
sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
 | 
			
		||||
 | 
			
		||||
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 | 
			
		||||
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 | 
			
		||||
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS)  = virtio-9p.o
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-synth.o
 | 
			
		||||
9pfs-nested-$(CONFIG_OPEN_BY_HANDLE) +=  virtio-9p-handle.o
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-proxy.o
 | 
			
		||||
 | 
			
		||||
hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# libdis
 | 
			
		||||
# NOTE: the disassembler code is only needed for debugging
 | 
			
		||||
 | 
			
		||||
libdis-y =
 | 
			
		||||
libdis-$(CONFIG_ALPHA_DIS) += alpha-dis.o
 | 
			
		||||
libdis-$(CONFIG_ARM_DIS) += arm-dis.o
 | 
			
		||||
libdis-$(CONFIG_CRIS_DIS) += cris-dis.o
 | 
			
		||||
libdis-$(CONFIG_HPPA_DIS) += hppa-dis.o
 | 
			
		||||
libdis-$(CONFIG_I386_DIS) += i386-dis.o
 | 
			
		||||
libdis-$(CONFIG_IA64_DIS) += ia64-dis.o
 | 
			
		||||
libdis-$(CONFIG_M68K_DIS) += m68k-dis.o
 | 
			
		||||
libdis-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o
 | 
			
		||||
libdis-$(CONFIG_MIPS_DIS) += mips-dis.o
 | 
			
		||||
libdis-$(CONFIG_PPC_DIS) += ppc-dis.o
 | 
			
		||||
libdis-$(CONFIG_S390_DIS) += s390-dis.o
 | 
			
		||||
libdis-$(CONFIG_SH4_DIS) += sh4-dis.o
 | 
			
		||||
libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
 | 
			
		||||
libdis-$(CONFIG_LM32_DIS) += lm32-dis.o
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# trace
 | 
			
		||||
 | 
			
		||||
ifeq ($(TRACE_BACKEND),dtrace)
 | 
			
		||||
TRACE_H_EXTRA_DEPS=trace-dtrace.h
 | 
			
		||||
endif
 | 
			
		||||
trace.h: trace.h-timestamp $(TRACE_H_EXTRA_DEPS)
 | 
			
		||||
trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
 | 
			
		||||
	$(call quiet-command,$(TRACETOOL) \
 | 
			
		||||
		--format=h \
 | 
			
		||||
		--backend=$(TRACE_BACKEND) \
 | 
			
		||||
		< $< > $@,"  GEN   trace.h")
 | 
			
		||||
	@cmp -s $@ trace.h || cp $@ trace.h
 | 
			
		||||
 | 
			
		||||
trace.c: trace.c-timestamp
 | 
			
		||||
trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
 | 
			
		||||
	$(call quiet-command,$(TRACETOOL) \
 | 
			
		||||
		--format=c \
 | 
			
		||||
		--backend=$(TRACE_BACKEND) \
 | 
			
		||||
		< $< > $@,"  GEN   trace.c")
 | 
			
		||||
	@cmp -s $@ trace.c || cp $@ trace.c
 | 
			
		||||
 | 
			
		||||
trace.o: trace.c $(GENERATED_HEADERS)
 | 
			
		||||
 | 
			
		||||
trace-dtrace.h: trace-dtrace.dtrace
 | 
			
		||||
	$(call quiet-command,dtrace -o $@ -h -s $<, "  GEN   trace-dtrace.h")
 | 
			
		||||
 | 
			
		||||
# Normal practice is to name DTrace probe file with a '.d' extension
 | 
			
		||||
# but that gets picked up by QEMU's Makefile as an external dependency
 | 
			
		||||
# rule file. So we use '.dtrace' instead
 | 
			
		||||
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
 | 
			
		||||
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
 | 
			
		||||
	$(call quiet-command,$(TRACETOOL) \
 | 
			
		||||
		--format=d \
 | 
			
		||||
		--backend=$(TRACE_BACKEND) \
 | 
			
		||||
		< $< > $@,"  GEN   trace-dtrace.dtrace")
 | 
			
		||||
	@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
 | 
			
		||||
 | 
			
		||||
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
 | 
			
		||||
	$(call quiet-command,dtrace -o $@ -G -s $<, "  GEN   trace-dtrace.o")
 | 
			
		||||
 | 
			
		||||
ifeq ($(LIBTOOL),)
 | 
			
		||||
trace-dtrace.lo: trace-dtrace.dtrace
 | 
			
		||||
	@echo "missing libtool. please install and rerun configure."; exit 1
 | 
			
		||||
else
 | 
			
		||||
trace-dtrace.lo: trace-dtrace.dtrace
 | 
			
		||||
	$(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, "  lt GEN trace-dtrace.o")
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
trace/simple.o: trace/simple.c $(GENERATED_HEADERS)
 | 
			
		||||
 | 
			
		||||
trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace.o
 | 
			
		||||
ifneq ($(TRACE_BACKEND),dtrace)
 | 
			
		||||
trace-obj-y = trace.o
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
trace-nested-$(CONFIG_TRACE_DEFAULT) += default.o
 | 
			
		||||
 | 
			
		||||
trace-nested-$(CONFIG_TRACE_SIMPLE) += simple.o
 | 
			
		||||
trace-obj-$(CONFIG_TRACE_SIMPLE) += qemu-timer-common.o
 | 
			
		||||
 | 
			
		||||
trace-nested-$(CONFIG_TRACE_STDERR) += stderr.o
 | 
			
		||||
 | 
			
		||||
trace-nested-y += control.o
 | 
			
		||||
 | 
			
		||||
trace-obj-y += $(addprefix trace/, $(trace-nested-y))
 | 
			
		||||
 | 
			
		||||
$(trace-obj-y): $(GENERATED_HEADERS)
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# smartcard
 | 
			
		||||
 | 
			
		||||
libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# qapi
 | 
			
		||||
 | 
			
		||||
qapi-nested-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
 | 
			
		||||
qapi-nested-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
 | 
			
		||||
qapi-nested-y += string-input-visitor.o string-output-visitor.o
 | 
			
		||||
qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 | 
			
		||||
 | 
			
		||||
common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o
 | 
			
		||||
common-obj-y += qmp.o hmp.o
 | 
			
		||||
 | 
			
		||||
universal-obj-y += $(qapi-obj-y)
 | 
			
		||||
 | 
			
		||||
######################################################################
 | 
			
		||||
# guest agent
 | 
			
		||||
 | 
			
		||||
qga-nested-y = commands.o guest-agent-command-state.o
 | 
			
		||||
qga-nested-$(CONFIG_POSIX) += commands-posix.o channel-posix.o
 | 
			
		||||
qga-nested-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o
 | 
			
		||||
qga-obj-y = $(addprefix qga/, $(qga-nested-y))
 | 
			
		||||
qga-obj-y += qemu-ga.o module.o
 | 
			
		||||
qga-obj-$(CONFIG_WIN32) += oslib-win32.o
 | 
			
		||||
qga-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-sockets.o qemu-option.o
 | 
			
		||||
 | 
			
		||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 | 
			
		||||
 | 
			
		||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS+=$(GLIB_CFLAGS)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										474
									
								
								Makefile.target
									
									
									
									
									
								
							
							
						
						
									
										474
									
								
								Makefile.target
									
									
									
									
									
								
							@@ -1,136 +1,109 @@
 | 
			
		||||
# -*- Mode: makefile -*-
 | 
			
		||||
 | 
			
		||||
# This needs to be defined before rules.mak
 | 
			
		||||
GENERATED_HEADERS = config-target.h
 | 
			
		||||
CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
 | 
			
		||||
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
 | 
			
		||||
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
 | 
			
		||||
 | 
			
		||||
include ../config-host.mak
 | 
			
		||||
include config-devices.mak
 | 
			
		||||
include config-target.mak
 | 
			
		||||
include $(SRC_PATH)/rules.mak
 | 
			
		||||
ifneq ($(HWDIR),)
 | 
			
		||||
include $(HWDIR)/config.mak
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
 | 
			
		||||
$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw)
 | 
			
		||||
ifdef CONFIG_LINUX
 | 
			
		||||
QEMU_CFLAGS += -I../linux-headers
 | 
			
		||||
endif
 | 
			
		||||
QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H
 | 
			
		||||
 | 
			
		||||
include $(SRC_PATH)/Makefile.objs
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS+=-I$(SRC_PATH)/include
 | 
			
		||||
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
 | 
			
		||||
QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -DNEED_CPU_H
 | 
			
		||||
 | 
			
		||||
ifdef CONFIG_USER_ONLY
 | 
			
		||||
# user emulator name
 | 
			
		||||
QEMU_PROG=qemu-$(TARGET_ARCH2)
 | 
			
		||||
else
 | 
			
		||||
# system emulator name
 | 
			
		||||
ifneq (,$(findstring -mwindows,$(LIBS)))
 | 
			
		||||
# Terminate program name with a 'w' because the linker builds a windows executable.
 | 
			
		||||
QEMU_PROGW=qemu-system-$(TARGET_ARCH2)w$(EXESUF)
 | 
			
		||||
endif # windows executable
 | 
			
		||||
ifeq ($(TARGET_ARCH), i386)
 | 
			
		||||
QEMU_PROG=qemu$(EXESUF)
 | 
			
		||||
else
 | 
			
		||||
QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
PROGS=$(QEMU_PROG)
 | 
			
		||||
ifdef QEMU_PROGW
 | 
			
		||||
PROGS+=$(QEMU_PROGW)
 | 
			
		||||
endif
 | 
			
		||||
STPFILES=
 | 
			
		||||
 | 
			
		||||
ifndef CONFIG_HAIKU
 | 
			
		||||
LIBS+=-lm
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
kvm.o kvm-all.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
 | 
			
		||||
 | 
			
		||||
CFLAGS += $(KVM_CFLAGS)
 | 
			
		||||
 | 
			
		||||
config-target.h: config-target.h-timestamp
 | 
			
		||||
config-target.h-timestamp: config-target.mak
 | 
			
		||||
 | 
			
		||||
ifdef CONFIG_TRACE_SYSTEMTAP
 | 
			
		||||
stap: $(QEMU_PROG).stp
 | 
			
		||||
 | 
			
		||||
ifdef CONFIG_USER_ONLY
 | 
			
		||||
TARGET_TYPE=user
 | 
			
		||||
else
 | 
			
		||||
TARGET_TYPE=system
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
$(QEMU_PROG).stp: $(SRC_PATH)/trace-events
 | 
			
		||||
	$(call quiet-command,$(TRACETOOL) \
 | 
			
		||||
		--format=stap \
 | 
			
		||||
		--backend=$(TRACE_BACKEND) \
 | 
			
		||||
		--binary=$(bindir)/$(QEMU_PROG) \
 | 
			
		||||
		--target-arch=$(TARGET_ARCH) \
 | 
			
		||||
		--target-type=$(TARGET_TYPE) \
 | 
			
		||||
		< $< > $@,"  GEN   $(QEMU_PROG).stp")
 | 
			
		||||
else
 | 
			
		||||
stap:
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
all: $(PROGS) stap
 | 
			
		||||
all: $(PROGS)
 | 
			
		||||
 | 
			
		||||
# Dummy command so that make thinks it has done something
 | 
			
		||||
	@true
 | 
			
		||||
 | 
			
		||||
#########################################################
 | 
			
		||||
# cpu emulator library
 | 
			
		||||
libobj-y = exec.o translate-all.o cpu-exec.o translate.o
 | 
			
		||||
libobj-y += tcg/tcg.o tcg/optimize.o
 | 
			
		||||
libobj-$(CONFIG_TCG_INTERPRETER) += tci.o
 | 
			
		||||
libobj-y += fpu/softfloat.o
 | 
			
		||||
ifneq ($(TARGET_BASE_ARCH), sparc)
 | 
			
		||||
ifneq ($(TARGET_BASE_ARCH), alpha)
 | 
			
		||||
libobj-y += op_helper.o
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
libobj-y += helper.o
 | 
			
		||||
ifneq ($(TARGET_BASE_ARCH), ppc)
 | 
			
		||||
libobj-y += cpu.o
 | 
			
		||||
endif
 | 
			
		||||
libobj-$(TARGET_SPARC64) += vis_helper.o
 | 
			
		||||
libobj-y = exec.o cpu-exec.o
 | 
			
		||||
libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o
 | 
			
		||||
libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o
 | 
			
		||||
libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o
 | 
			
		||||
libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
 | 
			
		||||
libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
 | 
			
		||||
libobj-y += op_helper.o helper.o
 | 
			
		||||
libobj-$(CONFIG_NEED_MMU) += mmu.o
 | 
			
		||||
 | 
			
		||||
libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
 | 
			
		||||
libobj-$(CONFIG_KVM) += qemu-kvm-helper.o
 | 
			
		||||
 | 
			
		||||
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 | 
			
		||||
ifeq ($(TARGET_BASE_ARCH), sparc)
 | 
			
		||||
libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
 | 
			
		||||
endif
 | 
			
		||||
libobj-$(TARGET_SPARC) += int32_helper.o
 | 
			
		||||
libobj-$(TARGET_SPARC64) += int64_helper.o
 | 
			
		||||
libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
 | 
			
		||||
libobj-$(TARGET_ALPHA) += alpha_palcode.o
 | 
			
		||||
 | 
			
		||||
# NOTE: the disassembler code is only needed for debugging
 | 
			
		||||
libobj-y += disas.o
 | 
			
		||||
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
 | 
			
		||||
libobj-$(CONFIG_ALPHA_DIS) += alpha-dis.o
 | 
			
		||||
libobj-$(CONFIG_ARM_DIS) += arm-dis.o
 | 
			
		||||
libobj-$(CONFIG_CRIS_DIS) += cris-dis.o
 | 
			
		||||
libobj-$(CONFIG_HPPA_DIS) += hppa-dis.o
 | 
			
		||||
libobj-$(CONFIG_I386_DIS) += i386-dis.o
 | 
			
		||||
libobj-$(CONFIG_M68K_DIS) += m68k-dis.o
 | 
			
		||||
libobj-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o
 | 
			
		||||
libobj-$(CONFIG_MIPS_DIS) += mips-dis.o
 | 
			
		||||
libobj-$(CONFIG_PPC_DIS) += ppc-dis.o
 | 
			
		||||
libobj-$(CONFIG_S390_DIS) += s390-dis.o
 | 
			
		||||
libobj-$(CONFIG_SH4_DIS) += sh4-dis.o
 | 
			
		||||
libobj-$(CONFIG_SPARC_DIS) += sparc-dis.o
 | 
			
		||||
 | 
			
		||||
tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci
 | 
			
		||||
# libqemu
 | 
			
		||||
 | 
			
		||||
$(libobj-y): $(GENERATED_HEADERS)
 | 
			
		||||
libqemu.a: $(libobj-y)
 | 
			
		||||
 | 
			
		||||
# HELPER_CFLAGS is used for all the legacy code compiled with static register
 | 
			
		||||
translate.o: translate.c cpu.h
 | 
			
		||||
 | 
			
		||||
translate-all.o: translate-all.c cpu.h
 | 
			
		||||
 | 
			
		||||
tcg/tcg.o: cpu.h
 | 
			
		||||
 | 
			
		||||
# HELPER_CFLAGS is used for all the code compiled with static register
 | 
			
		||||
# variables
 | 
			
		||||
ifneq ($(TARGET_BASE_ARCH), sparc)
 | 
			
		||||
op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
			
		||||
endif
 | 
			
		||||
user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
			
		||||
op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
			
		||||
 | 
			
		||||
# Note: this is a workaround. The real fix is to avoid compiling
 | 
			
		||||
# cpu_signal_handler() in user-exec.c.
 | 
			
		||||
# cpu_signal_handler() in cpu-exec.c.
 | 
			
		||||
signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
			
		||||
 | 
			
		||||
qemu-kvm-helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
			
		||||
 | 
			
		||||
#########################################################
 | 
			
		||||
# Linux user emulator target
 | 
			
		||||
 | 
			
		||||
ifdef CONFIG_LINUX_USER
 | 
			
		||||
 | 
			
		||||
$(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR))
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
 | 
			
		||||
VPATH+=:$(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
 | 
			
		||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
 | 
			
		||||
obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
 | 
			
		||||
      elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \
 | 
			
		||||
      user-exec.o $(oslib-obj-y)
 | 
			
		||||
      elfload.o linuxload.o uaccess.o gdbstub.o
 | 
			
		||||
 | 
			
		||||
obj-$(TARGET_HAS_BFLT) += flatload.o
 | 
			
		||||
obj-$(TARGET_HAS_ELFLOAD32) += elfload32.o
 | 
			
		||||
 | 
			
		||||
obj-$(TARGET_I386) += vm86.o
 | 
			
		||||
 | 
			
		||||
@@ -143,35 +116,46 @@ obj-arm-y += arm-semi.o
 | 
			
		||||
 | 
			
		||||
obj-m68k-y += m68k-sim.o m68k-semi.o
 | 
			
		||||
 | 
			
		||||
$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
 | 
			
		||||
 | 
			
		||||
obj-y += $(addprefix ../, $(universal-obj-y))
 | 
			
		||||
obj-y += $(addprefix ../libuser/, $(user-obj-y))
 | 
			
		||||
obj-y += $(addprefix ../libdis-user/, $(libdis-y))
 | 
			
		||||
obj-y += $(libobj-y)
 | 
			
		||||
ARLIBS=../libuser/libuser.a libqemu.a
 | 
			
		||||
 | 
			
		||||
endif #CONFIG_LINUX_USER
 | 
			
		||||
 | 
			
		||||
#########################################################
 | 
			
		||||
# Darwin user emulator target
 | 
			
		||||
 | 
			
		||||
ifdef CONFIG_DARWIN_USER
 | 
			
		||||
 | 
			
		||||
VPATH+=:$(SRC_PATH)/darwin-user
 | 
			
		||||
QEMU_CFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
 | 
			
		||||
 | 
			
		||||
# Leave some space for the regular program loading zone
 | 
			
		||||
LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
 | 
			
		||||
 | 
			
		||||
LIBS+=-lmx
 | 
			
		||||
 | 
			
		||||
obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \
 | 
			
		||||
        gdbstub.o
 | 
			
		||||
 | 
			
		||||
obj-i386-y += ioport-user.o
 | 
			
		||||
 | 
			
		||||
ARLIBS=../libuser/libuser.a libqemu.a
 | 
			
		||||
 | 
			
		||||
endif #CONFIG_DARWIN_USER
 | 
			
		||||
 | 
			
		||||
#########################################################
 | 
			
		||||
# BSD user emulator target
 | 
			
		||||
 | 
			
		||||
ifdef CONFIG_BSD_USER
 | 
			
		||||
 | 
			
		||||
$(call set-vpath, $(SRC_PATH)/bsd-user)
 | 
			
		||||
 | 
			
		||||
VPATH+=:$(SRC_PATH)/bsd-user
 | 
			
		||||
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
 | 
			
		||||
 | 
			
		||||
obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 | 
			
		||||
        gdbstub.o uaccess.o user-exec.o
 | 
			
		||||
        gdbstub.o uaccess.o
 | 
			
		||||
 | 
			
		||||
obj-i386-y += ioport-user.o
 | 
			
		||||
 | 
			
		||||
$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
 | 
			
		||||
 | 
			
		||||
obj-y += $(addprefix ../, $(universal-obj-y))
 | 
			
		||||
obj-y += $(addprefix ../libuser/, $(user-obj-y))
 | 
			
		||||
obj-y += $(addprefix ../libdis-user/, $(libdis-y))
 | 
			
		||||
obj-y += $(libobj-y)
 | 
			
		||||
ARLIBS=../libuser/libuser.a libqemu.a
 | 
			
		||||
 | 
			
		||||
endif #CONFIG_BSD_USER
 | 
			
		||||
 | 
			
		||||
@@ -179,134 +163,112 @@ endif #CONFIG_BSD_USER
 | 
			
		||||
# System emulator target
 | 
			
		||||
ifdef CONFIG_SOFTMMU
 | 
			
		||||
 | 
			
		||||
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o
 | 
			
		||||
obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
 | 
			
		||||
# virtio has to be here due to weird dependency between PCI and virtio-net.
 | 
			
		||||
# need to fix this properly
 | 
			
		||||
obj-$(CONFIG_NO_PCI) += pci-stub.o
 | 
			
		||||
obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
 | 
			
		||||
obj-$(CONFIG_VIRTIO) += virtio-scsi.o
 | 
			
		||||
obj-y += vhost_net.o
 | 
			
		||||
obj-$(CONFIG_VHOST_NET) += vhost.o
 | 
			
		||||
obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
 | 
			
		||||
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
 | 
			
		||||
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 | 
			
		||||
obj-$(CONFIG_NO_KVM) += kvm-stub.o
 | 
			
		||||
obj-$(CONFIG_VGA) += vga.o
 | 
			
		||||
obj-y += memory.o savevm.o cputlb.o
 | 
			
		||||
# MSI-X depends on kvm for interrupt injection,
 | 
			
		||||
# so moved it from Makefile.hw to Makefile.target for now
 | 
			
		||||
obj-y += msix.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 | 
			
		||||
LIBS+=-lz
 | 
			
		||||
 | 
			
		||||
obj-i386-$(CONFIG_KVM) += hyperv.o
 | 
			
		||||
sound-obj-y =
 | 
			
		||||
sound-obj-$(CONFIG_SB16) += sb16.o
 | 
			
		||||
sound-obj-$(CONFIG_ES1370) += es1370.o
 | 
			
		||||
sound-obj-$(CONFIG_AC97) += ac97.o
 | 
			
		||||
sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
 | 
			
		||||
sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
 | 
			
		||||
sound-obj-$(CONFIG_CS4231A) += cs4231a.o
 | 
			
		||||
 | 
			
		||||
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 | 
			
		||||
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 | 
			
		||||
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
 | 
			
		||||
QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 | 
			
		||||
 | 
			
		||||
# xen support
 | 
			
		||||
obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o
 | 
			
		||||
obj-$(CONFIG_NO_XEN) += xen-stub.o
 | 
			
		||||
# xen backend driver support
 | 
			
		||||
obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 | 
			
		||||
 | 
			
		||||
obj-i386-$(CONFIG_XEN) += xen_platform.o xen_apic.o
 | 
			
		||||
# USB layer
 | 
			
		||||
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 | 
			
		||||
 | 
			
		||||
# Inter-VM PCI shared memory
 | 
			
		||||
CONFIG_IVSHMEM =
 | 
			
		||||
ifeq ($(CONFIG_KVM), y)
 | 
			
		||||
  ifeq ($(CONFIG_PCI), y)
 | 
			
		||||
    CONFIG_IVSHMEM = y
 | 
			
		||||
  endif
 | 
			
		||||
endif
 | 
			
		||||
obj-$(CONFIG_IVSHMEM) += ivshmem.o
 | 
			
		||||
 | 
			
		||||
# Generic hotplugging
 | 
			
		||||
obj-y += device-hotplug.o
 | 
			
		||||
# PCI network cards
 | 
			
		||||
obj-y += eepro100.o
 | 
			
		||||
obj-y += pcnet.o
 | 
			
		||||
obj-y += rtl8139.o
 | 
			
		||||
obj-y += e1000.o
 | 
			
		||||
 | 
			
		||||
# Hardware support
 | 
			
		||||
obj-i386-y += mc146818rtc.o pc.o
 | 
			
		||||
obj-i386-y += apic_common.o apic.o kvmvapic.o
 | 
			
		||||
obj-i386-y += sga.o ioapic_common.o ioapic.o piix_pci.o
 | 
			
		||||
obj-i386-y += vmport.o
 | 
			
		||||
obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 | 
			
		||||
obj-i386-y += debugcon.o multiboot.o
 | 
			
		||||
obj-i386-y += pc_piix.o
 | 
			
		||||
obj-i386-y += pc_sysfw.o
 | 
			
		||||
obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o kvm/i8254.o
 | 
			
		||||
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 | 
			
		||||
obj-i386-y = ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/piix.o
 | 
			
		||||
obj-i386-y += pckbd.o $(sound-obj-y) dma.o
 | 
			
		||||
obj-i386-y += vga.o vga-pci.o vga-isa.o
 | 
			
		||||
obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 | 
			
		||||
obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
 | 
			
		||||
obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
 | 
			
		||||
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 | 
			
		||||
obj-i386-y += extboot.o
 | 
			
		||||
obj-i386-y += ne2000-isa.o
 | 
			
		||||
obj-i386-y += testdev.o
 | 
			
		||||
 | 
			
		||||
obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
 | 
			
		||||
obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
 | 
			
		||||
 | 
			
		||||
# Hardware support
 | 
			
		||||
obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
 | 
			
		||||
obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o
 | 
			
		||||
obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o
 | 
			
		||||
obj-ia64-y += usb-uhci.o
 | 
			
		||||
obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
 | 
			
		||||
 | 
			
		||||
# shared objects
 | 
			
		||||
obj-ppc-y = ppc.o ppc_booke.o
 | 
			
		||||
obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
 | 
			
		||||
obj-ppc-y += ide/cmd646.o
 | 
			
		||||
obj-ppc-y += vga.o vga-pci.o $(sound-obj-y) dma.o openpic.o
 | 
			
		||||
obj-ppc-y += cirrus_vga.o
 | 
			
		||||
# PREP target
 | 
			
		||||
obj-ppc-y += mc146818rtc.o
 | 
			
		||||
obj-ppc-y += ppc_prep.o
 | 
			
		||||
obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
 | 
			
		||||
obj-ppc-y += prep_pci.o ppc_prep.o ne2000-isa.o
 | 
			
		||||
# Mac shared devices
 | 
			
		||||
obj-ppc-y += macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o
 | 
			
		||||
# OldWorld PowerMac
 | 
			
		||||
obj-ppc-y += ppc_oldworld.o
 | 
			
		||||
obj-ppc-y += heathrow_pic.o grackle_pci.o ppc_oldworld.o
 | 
			
		||||
# NewWorld PowerMac
 | 
			
		||||
obj-ppc-y += ppc_newworld.o
 | 
			
		||||
# IBM pSeries (sPAPR)
 | 
			
		||||
obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
 | 
			
		||||
obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
 | 
			
		||||
obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o
 | 
			
		||||
obj-ppc-y += unin_pci.o ppc_newworld.o
 | 
			
		||||
# PowerPC 4xx boards
 | 
			
		||||
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 | 
			
		||||
obj-ppc-y += ppc440_bamboo.o
 | 
			
		||||
obj-ppc-y += pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 | 
			
		||||
obj-ppc-y += ppc440.o ppc440_bamboo.o
 | 
			
		||||
# PowerPC E500 boards
 | 
			
		||||
obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
 | 
			
		||||
# PowerPC 440 Xilinx ML507 reference board.
 | 
			
		||||
obj-ppc-y += virtex_ml507.o
 | 
			
		||||
obj-ppc-y += ppce500_pci.o ppce500_mpc8544ds.o
 | 
			
		||||
obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
 | 
			
		||||
obj-ppc-$(CONFIG_FDT) += device_tree.o
 | 
			
		||||
# PowerPC OpenPIC
 | 
			
		||||
obj-ppc-y += openpic.o
 | 
			
		||||
 | 
			
		||||
# Xilinx PPC peripherals
 | 
			
		||||
obj-ppc-y += xilinx_intc.o
 | 
			
		||||
obj-ppc-y += xilinx_timer.o
 | 
			
		||||
obj-ppc-y += xilinx_uartlite.o
 | 
			
		||||
obj-ppc-y += xilinx_ethlite.o
 | 
			
		||||
 | 
			
		||||
# LM32 boards
 | 
			
		||||
obj-lm32-y += lm32_boards.o
 | 
			
		||||
obj-lm32-y += milkymist.o
 | 
			
		||||
 | 
			
		||||
# LM32 peripherals
 | 
			
		||||
obj-lm32-y += lm32_pic.o
 | 
			
		||||
obj-lm32-y += lm32_juart.o
 | 
			
		||||
obj-lm32-y += lm32_timer.o
 | 
			
		||||
obj-lm32-y += lm32_uart.o
 | 
			
		||||
obj-lm32-y += lm32_sys.o
 | 
			
		||||
obj-lm32-y += milkymist-ac97.o
 | 
			
		||||
obj-lm32-y += milkymist-hpdmc.o
 | 
			
		||||
obj-lm32-y += milkymist-memcard.o
 | 
			
		||||
obj-lm32-y += milkymist-minimac2.o
 | 
			
		||||
obj-lm32-y += milkymist-pfpu.o
 | 
			
		||||
obj-lm32-y += milkymist-softusb.o
 | 
			
		||||
obj-lm32-y += milkymist-sysctl.o
 | 
			
		||||
obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o
 | 
			
		||||
obj-lm32-y += milkymist-uart.o
 | 
			
		||||
obj-lm32-y += milkymist-vgafb.o
 | 
			
		||||
obj-lm32-y += framebuffer.o
 | 
			
		||||
 | 
			
		||||
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 | 
			
		||||
obj-mips-y += mips_addr.o mips_timer.o mips_int.o
 | 
			
		||||
obj-mips-y += gt64xxx.o mc146818rtc.o
 | 
			
		||||
obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
 | 
			
		||||
obj-mips-y += mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
 | 
			
		||||
obj-mips-y += vga-pci.o vga-isa.o vga-isa-mm.o
 | 
			
		||||
obj-mips-y += g364fb.o jazz_led.o dp8393x.o
 | 
			
		||||
obj-mips-y += ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/piix.o
 | 
			
		||||
obj-mips-y += gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
 | 
			
		||||
obj-mips-y += piix4.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y)
 | 
			
		||||
obj-mips-y += mipsnet.o ne2000-isa.o
 | 
			
		||||
obj-mips-y += pflash_cfi01.o
 | 
			
		||||
obj-mips-y += vmware_vga.o
 | 
			
		||||
 | 
			
		||||
obj-microblaze-y = petalogix_s3adsp1800_mmu.o
 | 
			
		||||
obj-microblaze-y += petalogix_ml605_mmu.o
 | 
			
		||||
obj-microblaze-y += microblaze_boot.o
 | 
			
		||||
 | 
			
		||||
obj-microblaze-y += microblaze_pic_cpu.o
 | 
			
		||||
obj-microblaze-y += xilinx_intc.o
 | 
			
		||||
obj-microblaze-y += xilinx_timer.o
 | 
			
		||||
obj-microblaze-y += xilinx_uartlite.o
 | 
			
		||||
obj-microblaze-y += xilinx_ethlite.o
 | 
			
		||||
obj-microblaze-y += xilinx_axidma.o
 | 
			
		||||
obj-microblaze-y += xilinx_axienet.o
 | 
			
		||||
 | 
			
		||||
obj-microblaze-y += pflash_cfi02.o
 | 
			
		||||
 | 
			
		||||
obj-microblaze-$(CONFIG_FDT) += device_tree.o
 | 
			
		||||
 | 
			
		||||
# Boards
 | 
			
		||||
obj-cris-y = cris_pic_cpu.o
 | 
			
		||||
obj-cris-y += cris-boot.o
 | 
			
		||||
obj-cris-y += axis_dev88.o
 | 
			
		||||
obj-cris-y = cris_pic_cpu.o etraxfs.o axis_dev88.o
 | 
			
		||||
 | 
			
		||||
# IO blocks
 | 
			
		||||
obj-cris-y += etraxfs_dma.o
 | 
			
		||||
@@ -315,141 +277,91 @@ obj-cris-y += etraxfs_eth.o
 | 
			
		||||
obj-cris-y += etraxfs_timer.o
 | 
			
		||||
obj-cris-y += etraxfs_ser.o
 | 
			
		||||
 | 
			
		||||
ifeq ($(TARGET_ARCH), sparc64)
 | 
			
		||||
obj-sparc-y = sun4u.o apb_pci.o
 | 
			
		||||
obj-sparc-y += mc146818rtc.o
 | 
			
		||||
else
 | 
			
		||||
obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
 | 
			
		||||
obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
 | 
			
		||||
obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
 | 
			
		||||
obj-cris-y += pflash_cfi02.o
 | 
			
		||||
 | 
			
		||||
# GRLIB
 | 
			
		||||
obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
 | 
			
		||||
ifeq ($(TARGET_ARCH), sparc64)
 | 
			
		||||
obj-sparc-y = sun4u.o pckbd.o apb_pci.o
 | 
			
		||||
obj-sparc-y += ide/core.o ide/qdev.o ide/pci.o ide/cmd646.o
 | 
			
		||||
obj-sparc-y += vga.o vga-pci.o
 | 
			
		||||
obj-sparc-y += fdc.o mc146818rtc.o serial.o
 | 
			
		||||
obj-sparc-y += cirrus_vga.o parallel.o
 | 
			
		||||
else
 | 
			
		||||
obj-sparc-y = sun4m.o lance.o tcx.o iommu.o slavio_intctl.o
 | 
			
		||||
obj-sparc-y += slavio_timer.o slavio_misc.o fdc.o sparc32_dma.o
 | 
			
		||||
obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
 | 
			
		||||
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 | 
			
		||||
obj-arm-y += versatile_pci.o
 | 
			
		||||
obj-arm-y += versatile_i2c.o
 | 
			
		||||
obj-arm-y += cadence_uart.o
 | 
			
		||||
obj-arm-y += cadence_ttc.o
 | 
			
		||||
obj-arm-y += cadence_gem.o
 | 
			
		||||
obj-arm-y += xilinx_zynq.o zynq_slcr.o
 | 
			
		||||
obj-arm-y += arm_gic.o
 | 
			
		||||
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 | 
			
		||||
obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
 | 
			
		||||
obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
 | 
			
		||||
obj-arm-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
 | 
			
		||||
obj-arm-y += arm_l2x0.o
 | 
			
		||||
obj-arm-y += arm_mptimer.o a15mpcore.o
 | 
			
		||||
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
 | 
			
		||||
obj-arm-y += highbank.o
 | 
			
		||||
obj-arm-y += pl061.o
 | 
			
		||||
obj-arm-y += xgmac.o
 | 
			
		||||
obj-arm-y += arm-semi.o
 | 
			
		||||
obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 | 
			
		||||
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 | 
			
		||||
obj-arm-y += gumstix.o
 | 
			
		||||
obj-arm-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
 | 
			
		||||
obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
 | 
			
		||||
		omap_gpio.o omap_intc.o omap_uart.o
 | 
			
		||||
obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
 | 
			
		||||
		omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
 | 
			
		||||
obj-arm-y += pflash_cfi01.o gumstix.o
 | 
			
		||||
obj-arm-y += zaurus.o ide/core.o ide/microdrive.o serial.o spitz.o tosa.o tc6393xb.o
 | 
			
		||||
obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
 | 
			
		||||
obj-arm-y += omap2.o omap_dss.o soc_dma.o
 | 
			
		||||
obj-arm-y += omap_sx1.o palm.o tsc210x.o
 | 
			
		||||
obj-arm-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o
 | 
			
		||||
obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
 | 
			
		||||
obj-arm-y += mst_fpga.o mainstone.o
 | 
			
		||||
obj-arm-y += z2.o
 | 
			
		||||
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
 | 
			
		||||
obj-arm-y += musicpal.o pflash_cfi02.o bitbang_i2c.o marvell_88w8618_audio.o
 | 
			
		||||
obj-arm-y += framebuffer.o
 | 
			
		||||
obj-arm-y += vexpress.o
 | 
			
		||||
obj-arm-y += strongarm.o
 | 
			
		||||
obj-arm-y += collie.o
 | 
			
		||||
obj-arm-y += pl041.o lm4549.o
 | 
			
		||||
obj-arm-$(CONFIG_FDT) += device_tree.o
 | 
			
		||||
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
 | 
			
		||||
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
 | 
			
		||||
obj-arm-y += syborg_virtio.o
 | 
			
		||||
 | 
			
		||||
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 | 
			
		||||
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
 | 
			
		||||
obj-sh4-y += ide/mmio.o
 | 
			
		||||
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
 | 
			
		||||
obj-sh4-y += ide/core.o ide/mmio.o
 | 
			
		||||
 | 
			
		||||
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
 | 
			
		||||
obj-m68k-y += m68k-semi.o dummy_m68k.o
 | 
			
		||||
 | 
			
		||||
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 | 
			
		||||
 | 
			
		||||
obj-alpha-y = mc146818rtc.o
 | 
			
		||||
obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
 | 
			
		||||
ifeq ($(TARGET_ARCH), ia64)
 | 
			
		||||
firmware.o: firmware.c
 | 
			
		||||
	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
obj-xtensa-y += xtensa_pic.o
 | 
			
		||||
obj-xtensa-y += xtensa_sim.o
 | 
			
		||||
obj-xtensa-y += xtensa_lx60.o
 | 
			
		||||
obj-xtensa-y += xtensa-semi.o
 | 
			
		||||
obj-xtensa-y += core-dc232b.o
 | 
			
		||||
obj-xtensa-y += core-dc233c.o
 | 
			
		||||
obj-xtensa-y += core-fsf.o
 | 
			
		||||
main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 | 
			
		||||
 | 
			
		||||
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 | 
			
		||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 | 
			
		||||
 | 
			
		||||
monitor.o: hmp-commands.h qmp-commands-old.h
 | 
			
		||||
vl.o: qemu-options.h
 | 
			
		||||
 | 
			
		||||
$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
 | 
			
		||||
monitor.o: qemu-monitor.h
 | 
			
		||||
 | 
			
		||||
obj-y += $(addprefix ../, $(universal-obj-y))
 | 
			
		||||
obj-y += $(addprefix ../, $(common-obj-y))
 | 
			
		||||
obj-y += $(addprefix ../libdis/, $(libdis-y))
 | 
			
		||||
obj-y += $(libobj-y)
 | 
			
		||||
obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
 | 
			
		||||
obj-y += $(addprefix ../, $(trace-obj-y))
 | 
			
		||||
ARLIBS=../libqemu_common.a libqemu.a $(HWLIB)
 | 
			
		||||
 | 
			
		||||
endif # CONFIG_SOFTMMU
 | 
			
		||||
 | 
			
		||||
ifndef CONFIG_LINUX_USER
 | 
			
		||||
ifndef CONFIG_BSD_USER
 | 
			
		||||
# libcacard needs qemu-thread support, and besides is only needed by devices
 | 
			
		||||
# so not requires with linux-user / bsd-user targets
 | 
			
		||||
obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y))
 | 
			
		||||
endif # CONFIG_BSD_USER
 | 
			
		||||
endif # CONFIG_LINUX_USER
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 | 
			
		||||
 | 
			
		||||
ifdef QEMU_PROGW
 | 
			
		||||
# The linker builds a windows executable. Make also a console executable.
 | 
			
		||||
$(QEMU_PROGW): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
 | 
			
		||||
	$(call LINK,$^)
 | 
			
		||||
$(QEMU_PROG): $(QEMU_PROGW)
 | 
			
		||||
	$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG),"  GEN   $(TARGET_DIR)$(QEMU_PROG)")
 | 
			
		||||
else
 | 
			
		||||
$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
 | 
			
		||||
	$(call LINK,$^)
 | 
			
		||||
endif
 | 
			
		||||
$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) $(ARLIBS)
 | 
			
		||||
	$(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y))
 | 
			
		||||
 | 
			
		||||
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
 | 
			
		||||
	$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"  GEN   $(TARGET_DIR)$@")
 | 
			
		||||
 | 
			
		||||
hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 | 
			
		||||
gdbstub-xml.c: $(TARGET_XML_FILES) feature_to_c.sh
 | 
			
		||||
	$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES),"  GEN   $(TARGET_DIR)$@")
 | 
			
		||||
 | 
			
		||||
qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 | 
			
		||||
qemu-options.h: $(SRC_PATH)/qemu-options.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 | 
			
		||||
 | 
			
		||||
qemu-monitor.h: $(SRC_PATH)/qemu-monitor.hx
 | 
			
		||||
	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
 | 
			
		||||
	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o kvm/*.o
 | 
			
		||||
	rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
 | 
			
		||||
ifdef CONFIG_TRACE_SYSTEMTAP
 | 
			
		||||
	rm -f *.stp
 | 
			
		||||
endif
 | 
			
		||||
	rm -f *.d */*.d tcg/*.o ide/*.o
 | 
			
		||||
	rm -f qemu-options.h qemu-monitor.h gdbstub-xml.c
 | 
			
		||||
 | 
			
		||||
install: all
 | 
			
		||||
ifneq ($(PROGS),)
 | 
			
		||||
	$(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)"
 | 
			
		||||
ifneq ($(STRIP),)
 | 
			
		||||
	$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
ifdef CONFIG_TRACE_SYSTEMTAP
 | 
			
		||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
 | 
			
		||||
	$(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
 | 
			
		||||
	$(INSTALL) -m 755 $(STRIP_OPT) $(PROGS) "$(DESTDIR)$(bindir)"
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Include automatically generated dependency files
 | 
			
		||||
 
 | 
			
		||||
@@ -6,21 +6,27 @@ include $(SRC_PATH)/rules.mak
 | 
			
		||||
 | 
			
		||||
.PHONY: all
 | 
			
		||||
 | 
			
		||||
$(call set-vpath, $(SRC_PATH))
 | 
			
		||||
# Do not take %.o from $(SRC_PATH), only %.c and %.h
 | 
			
		||||
# All %.o for user targets should be built with -fpie, when
 | 
			
		||||
# configured with --enable-user-pie, so we don't want to
 | 
			
		||||
# take %.o from $(SRC_PATH), since they built without -fpie
 | 
			
		||||
vpath %.c %.h $(SRC_PATH)
 | 
			
		||||
 | 
			
		||||
QEMU_CFLAGS+=-I..
 | 
			
		||||
QEMU_CFLAGS += -I$(SRC_PATH)/include
 | 
			
		||||
 | 
			
		||||
include $(SRC_PATH)/Makefile.objs
 | 
			
		||||
obj-y =
 | 
			
		||||
obj-y += envlist.o path.o
 | 
			
		||||
obj-y += tcg-runtime.o host-utils.o
 | 
			
		||||
obj-y += cutils.o cache-utils.o
 | 
			
		||||
 | 
			
		||||
all: $(user-obj-y)
 | 
			
		||||
all: libuser.a
 | 
			
		||||
# Dummy command so that make thinks it has done something
 | 
			
		||||
	@true
 | 
			
		||||
 | 
			
		||||
libuser.a: $(obj-y)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	for d in . trace; do \
 | 
			
		||||
	rm -f $$d/*.o $$d/*.d $$d/*.a $$d/*~; \
 | 
			
		||||
	done
 | 
			
		||||
	rm -f *.o *.d *.a *~
 | 
			
		||||
 | 
			
		||||
# Include automatically generated dependency files
 | 
			
		||||
-include $(wildcard *.d */*.d)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								QMP/README
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								QMP/README
									
									
									
									
									
								
							@@ -7,82 +7,57 @@ Introduction
 | 
			
		||||
The QEMU Monitor Protocol (QMP) allows applications to communicate with
 | 
			
		||||
QEMU's Monitor.
 | 
			
		||||
 | 
			
		||||
QMP is JSON[1] based and currently has the following features:
 | 
			
		||||
QMP is JSON[1] based and has the following features:
 | 
			
		||||
 | 
			
		||||
- Lightweight, text-based, easy to parse data format
 | 
			
		||||
- Asynchronous messages support (ie. events)
 | 
			
		||||
- Capabilities Negotiation
 | 
			
		||||
- Asynchronous events support 
 | 
			
		||||
- Stability
 | 
			
		||||
 | 
			
		||||
For detailed information on QMP's usage, please, refer to the following files:
 | 
			
		||||
For more information, please, refer to the following files:
 | 
			
		||||
 | 
			
		||||
o qmp-spec.txt    QEMU Monitor Protocol current specification
 | 
			
		||||
o qmp-commands.txt  QMP supported commands (auto-generated at build-time)
 | 
			
		||||
o qmp-events.txt  List of available asynchronous events
 | 
			
		||||
 | 
			
		||||
There is also a simple Python script called 'qmp-shell' available.
 | 
			
		||||
 | 
			
		||||
IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
 | 
			
		||||
section in the qmp-commands.txt file before making any serious use of QMP.
 | 
			
		||||
There are also two simple Python scripts available:
 | 
			
		||||
 | 
			
		||||
o qmp-shell       A shell
 | 
			
		||||
o vm-info         Show some information about the Virtual Machine
 | 
			
		||||
 | 
			
		||||
[1] http://www.json.org
 | 
			
		||||
 | 
			
		||||
Usage
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
To enable QMP, you need a QEMU monitor instance in "control mode". There are
 | 
			
		||||
two ways of doing this.
 | 
			
		||||
To enable QMP, QEMU has to be started in "control mode". There are
 | 
			
		||||
two ways of doing this, the simplest one is using the the '-qmp'
 | 
			
		||||
command-line option.
 | 
			
		||||
 | 
			
		||||
The simplest one is using the '-qmp' command-line option. The following
 | 
			
		||||
example makes QMP available on localhost port 4444:
 | 
			
		||||
For example:
 | 
			
		||||
 | 
			
		||||
  $ qemu [...] -qmp tcp:localhost:4444,server
 | 
			
		||||
$ qemu [...] -qmp tcp:localhost:4444,server
 | 
			
		||||
 | 
			
		||||
However, in order to have more complex combinations, like multiple monitors,
 | 
			
		||||
the '-mon' command-line option should be used along with the '-chardev' one.
 | 
			
		||||
For instance, the following example creates one user monitor on stdio and one
 | 
			
		||||
QMP monitor on localhost port 4444.
 | 
			
		||||
Will start QEMU in control mode, waiting for a client TCP connection
 | 
			
		||||
on localhost port 4444.
 | 
			
		||||
 | 
			
		||||
   $ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
 | 
			
		||||
                -chardev socket,id=mon1,host=localhost,port=4444,server \
 | 
			
		||||
                -mon chardev=mon1,mode=control
 | 
			
		||||
 | 
			
		||||
Please, refer to QEMU's manpage for more information.
 | 
			
		||||
It is also possible to use the '-mon' command-line option to have
 | 
			
		||||
more complex combinations. Please, refer to the QEMU's manpage for
 | 
			
		||||
more information.
 | 
			
		||||
 | 
			
		||||
Simple Testing
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
To manually test QMP one can connect with telnet and issue commands by hand:
 | 
			
		||||
To manually test QMP one can connect with telnet and issue commands:
 | 
			
		||||
 | 
			
		||||
$ telnet localhost 4444
 | 
			
		||||
Trying 127.0.0.1...
 | 
			
		||||
Connected to localhost.
 | 
			
		||||
Escape character is '^]'.
 | 
			
		||||
{"QMP": {"version": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}, "capabilities": []}}
 | 
			
		||||
{ "execute": "qmp_capabilities" }
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"QMP": {"capabilities": []}}
 | 
			
		||||
{ "execute": "query-version" }
 | 
			
		||||
{"return": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}}
 | 
			
		||||
{"return": {"qemu": "0.11.50", "package": ""}}
 | 
			
		||||
 | 
			
		||||
Development Process
 | 
			
		||||
-------------------
 | 
			
		||||
Contact
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
When changing QMP's interface (by adding new commands, events or modifying
 | 
			
		||||
existing ones) it's mandatory to update the relevant documentation, which is
 | 
			
		||||
one (or more) of the files listed in the 'Introduction' section*.
 | 
			
		||||
 | 
			
		||||
Also, it's strongly recommended to send the documentation patch first, before
 | 
			
		||||
doing any code change. This is so because:
 | 
			
		||||
 | 
			
		||||
  1. Avoids the code dictating the interface
 | 
			
		||||
 | 
			
		||||
  2. Review can improve your interface.  Letting that happen before
 | 
			
		||||
     you implement it can save you work.
 | 
			
		||||
 | 
			
		||||
* The qmp-commands.txt file is generated from the qmp-commands.hx one, which
 | 
			
		||||
  is the file that should be edited.
 | 
			
		||||
 | 
			
		||||
Homepage
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
http://wiki.qemu.org/QMP
 | 
			
		||||
http://www.linux-kvm.org/page/MonitorProtocol
 | 
			
		||||
Luiz Fernando N. Capitulino <lcapitulino@redhat.com>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										126
									
								
								QMP/qmp
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								QMP/qmp
									
									
									
									
									
								
							@@ -1,126 +0,0 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
#
 | 
			
		||||
# QMP command line tool
 | 
			
		||||
#
 | 
			
		||||
# Copyright IBM, Corp. 2011
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
#
 | 
			
		||||
# This work is licensed under the terms of the GNU GPLv2 or later.
 | 
			
		||||
# See the COPYING file in the top-level directory.
 | 
			
		||||
 | 
			
		||||
import sys, os
 | 
			
		||||
from qmp import QEMUMonitorProtocol
 | 
			
		||||
 | 
			
		||||
def print_response(rsp, prefix=[]):
 | 
			
		||||
    if type(rsp) == list:
 | 
			
		||||
        i = 0
 | 
			
		||||
        for item in rsp:
 | 
			
		||||
            if prefix == []:
 | 
			
		||||
                prefix = ['item']
 | 
			
		||||
            print_response(item, prefix[:-1] + ['%s[%d]' % (prefix[-1], i)])
 | 
			
		||||
            i += 1
 | 
			
		||||
    elif type(rsp) == dict:
 | 
			
		||||
        for key in rsp.keys():
 | 
			
		||||
            print_response(rsp[key], prefix + [key])
 | 
			
		||||
    else:
 | 
			
		||||
        if len(prefix):
 | 
			
		||||
            print '%s: %s' % ('.'.join(prefix), rsp)
 | 
			
		||||
        else:
 | 
			
		||||
            print '%s' % (rsp)
 | 
			
		||||
 | 
			
		||||
def main(args):
 | 
			
		||||
    path = None
 | 
			
		||||
 | 
			
		||||
    # Use QMP_PATH if it's set
 | 
			
		||||
    if os.environ.has_key('QMP_PATH'):
 | 
			
		||||
        path = os.environ['QMP_PATH']
 | 
			
		||||
 | 
			
		||||
    while len(args):
 | 
			
		||||
        arg = args[0]
 | 
			
		||||
 | 
			
		||||
        if arg.startswith('--'):
 | 
			
		||||
            arg = arg[2:]
 | 
			
		||||
            if arg.find('=') == -1:
 | 
			
		||||
                value = True
 | 
			
		||||
            else:
 | 
			
		||||
                arg, value = arg.split('=', 1)
 | 
			
		||||
 | 
			
		||||
            if arg in ['path']:
 | 
			
		||||
                if type(value) == str:
 | 
			
		||||
                    path = value
 | 
			
		||||
            elif arg in ['help']:
 | 
			
		||||
                os.execlp('man', 'man', 'qmp')
 | 
			
		||||
            else:
 | 
			
		||||
                print 'Unknown argument "%s"' % arg
 | 
			
		||||
 | 
			
		||||
            args = args[1:]
 | 
			
		||||
        else:
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
    if not path:
 | 
			
		||||
        print "QMP path isn't set, use --path=qmp-monitor-address or set QMP_PATH"
 | 
			
		||||
        return 1
 | 
			
		||||
 | 
			
		||||
    if len(args):
 | 
			
		||||
        command, args = args[0], args[1:]
 | 
			
		||||
    else:
 | 
			
		||||
        print 'No command found'
 | 
			
		||||
        print 'Usage: "qmp [--path=qmp-monitor-address] qmp-cmd arguments"'
 | 
			
		||||
        return 1
 | 
			
		||||
 | 
			
		||||
    if command in ['help']:
 | 
			
		||||
        os.execlp('man', 'man', 'qmp')
 | 
			
		||||
 | 
			
		||||
    srv = QEMUMonitorProtocol(path)
 | 
			
		||||
    srv.connect()
 | 
			
		||||
 | 
			
		||||
    def do_command(srv, cmd, **kwds):
 | 
			
		||||
        rsp = srv.cmd(cmd, kwds)
 | 
			
		||||
        if rsp.has_key('error'):
 | 
			
		||||
            raise Exception(rsp['error']['desc'])
 | 
			
		||||
        return rsp['return']
 | 
			
		||||
 | 
			
		||||
    commands = map(lambda x: x['name'], do_command(srv, 'query-commands'))
 | 
			
		||||
 | 
			
		||||
    srv.close()
 | 
			
		||||
 | 
			
		||||
    if command not in commands:
 | 
			
		||||
        fullcmd = 'qmp-%s' % command
 | 
			
		||||
        try:
 | 
			
		||||
            os.environ['QMP_PATH'] = path
 | 
			
		||||
            os.execvp(fullcmd, [fullcmd] + args)
 | 
			
		||||
        except OSError, (errno, msg):
 | 
			
		||||
            if errno == 2:
 | 
			
		||||
                print 'Command "%s" not found.' % (fullcmd)
 | 
			
		||||
                return 1
 | 
			
		||||
            raise
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    srv = QEMUMonitorProtocol(path)
 | 
			
		||||
    srv.connect()
 | 
			
		||||
 | 
			
		||||
    arguments = {}
 | 
			
		||||
    for arg in args:
 | 
			
		||||
        if not arg.startswith('--'):
 | 
			
		||||
            print 'Unknown argument "%s"' % arg
 | 
			
		||||
            return 1
 | 
			
		||||
 | 
			
		||||
        arg = arg[2:]
 | 
			
		||||
        if arg.find('=') == -1:
 | 
			
		||||
            value = True
 | 
			
		||||
        else:
 | 
			
		||||
            arg, value = arg.split('=', 1)
 | 
			
		||||
 | 
			
		||||
        if arg in ['help']:
 | 
			
		||||
            os.execlp('man', 'man', 'qmp-%s' % command)
 | 
			
		||||
            return 1
 | 
			
		||||
 | 
			
		||||
        arguments[arg] = value
 | 
			
		||||
 | 
			
		||||
    rsp = do_command(srv, command, **arguments)
 | 
			
		||||
    print_response(rsp)
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    sys.exit(main(sys.argv[1:]))
 | 
			
		||||
@@ -1,337 +1,26 @@
 | 
			
		||||
                   QEMU Monitor Protocol Events
 | 
			
		||||
                   ============================
 | 
			
		||||
                   QEMU Monitor Protocol: Events
 | 
			
		||||
                   =============================
 | 
			
		||||
 | 
			
		||||
BLOCK_IO_ERROR
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
Emitted when a disk I/O error occurs.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "device": device name (json-string)
 | 
			
		||||
- "operation": I/O operation (json-string, "read" or "write")
 | 
			
		||||
- "action": action that has been taken, it's one of the following (json-string):
 | 
			
		||||
    "ignore": error has been ignored
 | 
			
		||||
    "report": error has been reported to the device
 | 
			
		||||
    "stop": error caused VM to be stopped
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "BLOCK_IO_ERROR",
 | 
			
		||||
    "data": { "device": "ide0-hd1",
 | 
			
		||||
              "operation": "write",
 | 
			
		||||
              "action": "stop" },
 | 
			
		||||
    "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
 | 
			
		||||
 | 
			
		||||
Note: If action is "stop", a STOP event will eventually follow the
 | 
			
		||||
BLOCK_IO_ERROR event.
 | 
			
		||||
 | 
			
		||||
DEVICE_TRAY_MOVED
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
It's emitted whenever the tray of a removable device is moved by the guest
 | 
			
		||||
or by HMP/QMP commands.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "device": device name (json-string)
 | 
			
		||||
- "tray-open": true if the tray has been opened or false if it has been closed
 | 
			
		||||
               (json-bool)
 | 
			
		||||
 | 
			
		||||
{ "event": "DEVICE_TRAY_MOVED",
 | 
			
		||||
  "data": { "device": "ide1-cd0",
 | 
			
		||||
            "tray-open": true
 | 
			
		||||
  },
 | 
			
		||||
  "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
 | 
			
		||||
 | 
			
		||||
RESET
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
Emitted when the Virtual Machine is reseted.
 | 
			
		||||
1 SHUTDOWN
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
Description: Issued when the Virtual Machine is powered down.
 | 
			
		||||
Data: None.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
2 RESET
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
{ "event": "RESET",
 | 
			
		||||
    "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
 | 
			
		||||
Description: Issued when the Virtual Machine is reseted.
 | 
			
		||||
Data: None.
 | 
			
		||||
 | 
			
		||||
RESUME
 | 
			
		||||
3 STOP
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
Emitted when the Virtual Machine resumes execution.
 | 
			
		||||
 | 
			
		||||
Description: Issued when the Virtual Machine is stopped.
 | 
			
		||||
Data: None.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "RESUME",
 | 
			
		||||
    "timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
 | 
			
		||||
 | 
			
		||||
RTC_CHANGE
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
Emitted when the guest changes the RTC time.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "offset": delta against the host UTC in seconds (json-number)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "RTC_CHANGE",
 | 
			
		||||
    "data": { "offset": 78 },
 | 
			
		||||
    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
 | 
			
		||||
 | 
			
		||||
SHUTDOWN
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
Emitted when the Virtual Machine is powered down.
 | 
			
		||||
4 DEBUG
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
Description: Issued when the Virtual Machine enters debug mode.
 | 
			
		||||
Data: None.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "SHUTDOWN",
 | 
			
		||||
    "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
 | 
			
		||||
 | 
			
		||||
Note: If the command-line option "-no-shutdown" has been specified, a STOP
 | 
			
		||||
event will eventually follow the SHUTDOWN event.
 | 
			
		||||
 | 
			
		||||
STOP
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
Emitted when the Virtual Machine is stopped.
 | 
			
		||||
 | 
			
		||||
Data: None.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "STOP",
 | 
			
		||||
    "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
 | 
			
		||||
 | 
			
		||||
VNC_CONNECTED
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Emitted when a VNC client establishes a connection.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "server": Server information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "service": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
  - "auth": authentication method (json-string, optional)
 | 
			
		||||
- "client": Client information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "service": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "VNC_CONNECTED",
 | 
			
		||||
    "data": {
 | 
			
		||||
        "server": { "auth": "sasl", "family": "ipv4",
 | 
			
		||||
                    "service": "5901", "host": "0.0.0.0" },
 | 
			
		||||
        "client": { "family": "ipv4", "service": "58425",
 | 
			
		||||
                    "host": "127.0.0.1" } },
 | 
			
		||||
    "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Note: This event is emitted before any authentication takes place, thus
 | 
			
		||||
the authentication ID is not provided.
 | 
			
		||||
 | 
			
		||||
VNC_DISCONNECTED
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
Emitted when the connection is closed.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "server": Server information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "service": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
  - "auth": authentication method (json-string, optional)
 | 
			
		||||
- "client": Client information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "service": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
  - "x509_dname": TLS dname (json-string, optional)
 | 
			
		||||
  - "sasl_username": SASL username (json-string, optional)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "VNC_DISCONNECTED",
 | 
			
		||||
    "data": {
 | 
			
		||||
        "server": { "auth": "sasl", "family": "ipv4",
 | 
			
		||||
                    "service": "5901", "host": "0.0.0.0" },
 | 
			
		||||
        "client": { "family": "ipv4", "service": "58425",
 | 
			
		||||
                    "host": "127.0.0.1", "sasl_username": "luiz" } },
 | 
			
		||||
    "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
 | 
			
		||||
 | 
			
		||||
VNC_INITIALIZED
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
Emitted after authentication takes place (if any) and the VNC session is
 | 
			
		||||
made active.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "server": Server information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "service": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
  - "auth": authentication method (json-string, optional)
 | 
			
		||||
- "client": Client information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "service": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
  - "x509_dname": TLS dname (json-string, optional)
 | 
			
		||||
  - "sasl_username": SASL username (json-string, optional)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "VNC_INITIALIZED",
 | 
			
		||||
    "data": {
 | 
			
		||||
        "server": { "auth": "sasl", "family": "ipv4",
 | 
			
		||||
                    "service": "5901", "host": "0.0.0.0"},
 | 
			
		||||
        "client": { "family": "ipv4", "service": "46089",
 | 
			
		||||
                    "host": "127.0.0.1", "sasl_username": "luiz" } },
 | 
			
		||||
        "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
 | 
			
		||||
 | 
			
		||||
SPICE_CONNECTED, SPICE_DISCONNECTED
 | 
			
		||||
-----------------------------------
 | 
			
		||||
 | 
			
		||||
Emitted when a SPICE client connects or disconnects.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "server": Server information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "port": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
- "client": Client information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "port": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
 | 
			
		||||
  "event": "SPICE_CONNECTED",
 | 
			
		||||
  "data": {
 | 
			
		||||
    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
 | 
			
		||||
    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
 | 
			
		||||
}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SPICE_INITIALIZED
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
Emitted after initial handshake and authentication takes place (if any)
 | 
			
		||||
and the SPICE channel is up'n'running
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "server": Server information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "port": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
  - "auth": authentication method (json-string, optional)
 | 
			
		||||
- "client": Client information (json-object)
 | 
			
		||||
  - "host": IP address (json-string)
 | 
			
		||||
  - "port": port number (json-string)
 | 
			
		||||
  - "family": address family (json-string, "ipv4" or "ipv6")
 | 
			
		||||
  - "connection-id": spice connection id.  All channels with the same id
 | 
			
		||||
                     belong to the same spice session (json-int)
 | 
			
		||||
  - "channel-type": channel type.  "1" is the main control channel, filter for
 | 
			
		||||
                    this one if you want track spice sessions only (json-int)
 | 
			
		||||
  - "channel-id": channel id.  Usually "0", might be different needed when
 | 
			
		||||
                  multiple channels of the same type exist, such as multiple
 | 
			
		||||
                  display channels in a multihead setup (json-int)
 | 
			
		||||
  - "tls": whevener the channel is encrypted (json-bool)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
 | 
			
		||||
  "event": "SPICE_INITIALIZED",
 | 
			
		||||
  "data": {"server": {"auth": "spice", "port": "5921",
 | 
			
		||||
                      "family": "ipv4", "host": "127.0.0.1"},
 | 
			
		||||
           "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
 | 
			
		||||
                      "connection-id": 1804289383, "host": "127.0.0.1",
 | 
			
		||||
                      "channel-id": 0, "tls": true}
 | 
			
		||||
}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
WATCHDOG
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
Emitted when the watchdog device's timer is expired.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "action": Action that has been taken, it's one of the following (json-string):
 | 
			
		||||
            "reset", "shutdown", "poweroff", "pause", "debug", or "none"
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "WATCHDOG",
 | 
			
		||||
     "data": { "action": "reset" },
 | 
			
		||||
     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
 | 
			
		||||
 | 
			
		||||
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
 | 
			
		||||
followed respectively by the RESET, SHUTDOWN, or STOP events.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BLOCK_JOB_COMPLETED
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
Emitted when a block job has completed.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "type":     Job type ("stream" for image streaming, json-string)
 | 
			
		||||
- "device":   Device name (json-string)
 | 
			
		||||
- "len":      Maximum progress value (json-int)
 | 
			
		||||
- "offset":   Current progress value (json-int)
 | 
			
		||||
              On success this is equal to len.
 | 
			
		||||
              On failure this is less than len.
 | 
			
		||||
- "speed":    Rate limit, bytes per second (json-int)
 | 
			
		||||
- "error":    Error message (json-string, optional)
 | 
			
		||||
              Only present on failure.  This field contains a human-readable
 | 
			
		||||
              error message.  There are no semantics other than that streaming
 | 
			
		||||
              has failed and clients should not try to interpret the error
 | 
			
		||||
              string.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "BLOCK_JOB_COMPLETED",
 | 
			
		||||
     "data": { "type": "stream", "device": "virtio-disk0",
 | 
			
		||||
               "len": 10737418240, "offset": 10737418240,
 | 
			
		||||
               "speed": 0 },
 | 
			
		||||
     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BLOCK_JOB_CANCELLED
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
Emitted when a block job has been cancelled.
 | 
			
		||||
 | 
			
		||||
Data:
 | 
			
		||||
 | 
			
		||||
- "type":     Job type ("stream" for image streaming, json-string)
 | 
			
		||||
- "device":   Device name (json-string)
 | 
			
		||||
- "len":      Maximum progress value (json-int)
 | 
			
		||||
- "offset":   Current progress value (json-int)
 | 
			
		||||
              On success this is equal to len.
 | 
			
		||||
              On failure this is less than len.
 | 
			
		||||
- "speed":    Rate limit, bytes per second (json-int)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
{ "event": "BLOCK_JOB_CANCELLED",
 | 
			
		||||
     "data": { "type": "stream", "device": "virtio-disk0",
 | 
			
		||||
               "len": 10737418240, "offset": 134217728,
 | 
			
		||||
               "speed": 0 },
 | 
			
		||||
     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										259
									
								
								QMP/qmp-shell
									
									
									
									
									
								
							
							
						
						
									
										259
									
								
								QMP/qmp-shell
									
									
									
									
									
								
							@@ -1,8 +1,8 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
#
 | 
			
		||||
# Low-level QEMU shell on top of QMP.
 | 
			
		||||
# Simple QEMU shell on top of QMP
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2009, 2010 Red Hat Inc.
 | 
			
		||||
# Copyright (C) 2009 Red Hat Inc.
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Luiz Capitulino <lcapitulino@redhat.com>
 | 
			
		||||
@@ -14,11 +14,11 @@
 | 
			
		||||
#
 | 
			
		||||
# Start QEMU with:
 | 
			
		||||
#
 | 
			
		||||
# # qemu [...] -qmp unix:./qmp-sock,server
 | 
			
		||||
# $ qemu [...] -monitor control,unix:./qmp,server
 | 
			
		||||
#
 | 
			
		||||
# Run the shell:
 | 
			
		||||
#
 | 
			
		||||
# $ qmp-shell ./qmp-sock
 | 
			
		||||
# $ qmp-shell ./qmp
 | 
			
		||||
#
 | 
			
		||||
# Commands have the following format:
 | 
			
		||||
#
 | 
			
		||||
@@ -26,234 +26,47 @@
 | 
			
		||||
#
 | 
			
		||||
# For example:
 | 
			
		||||
#
 | 
			
		||||
# (QEMU) device_add driver=e1000 id=net1
 | 
			
		||||
# {u'return': {}}
 | 
			
		||||
# (QEMU)
 | 
			
		||||
# (QEMU) info item=network
 | 
			
		||||
 | 
			
		||||
import qmp
 | 
			
		||||
import readline
 | 
			
		||||
import sys
 | 
			
		||||
from sys import argv,exit
 | 
			
		||||
 | 
			
		||||
class QMPCompleter(list):
 | 
			
		||||
    def complete(self, text, state):
 | 
			
		||||
        for cmd in self:
 | 
			
		||||
            if cmd.startswith(text):
 | 
			
		||||
                if not state:
 | 
			
		||||
                    return cmd
 | 
			
		||||
                else:
 | 
			
		||||
                    state -= 1
 | 
			
		||||
 | 
			
		||||
class QMPShellError(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class QMPShellBadPort(QMPShellError):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
 | 
			
		||||
#       _execute_cmd()). Let's design a better one.
 | 
			
		||||
class QMPShell(qmp.QEMUMonitorProtocol):
 | 
			
		||||
    def __init__(self, address):
 | 
			
		||||
        qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
 | 
			
		||||
        self._greeting = None
 | 
			
		||||
        self._completer = None
 | 
			
		||||
 | 
			
		||||
    def __get_address(self, arg):
 | 
			
		||||
        """
 | 
			
		||||
        Figure out if the argument is in the port:host form, if it's not it's
 | 
			
		||||
        probably a file path.
 | 
			
		||||
        """
 | 
			
		||||
        addr = arg.split(':')
 | 
			
		||||
        if len(addr) == 2:
 | 
			
		||||
            try:
 | 
			
		||||
                port = int(addr[1])
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                raise QMPShellBadPort
 | 
			
		||||
            return ( addr[0], port )
 | 
			
		||||
        # socket path
 | 
			
		||||
        return arg
 | 
			
		||||
 | 
			
		||||
    def _fill_completion(self):
 | 
			
		||||
        for cmd in self.cmd('query-commands')['return']:
 | 
			
		||||
            self._completer.append(cmd['name'])
 | 
			
		||||
 | 
			
		||||
    def __completer_setup(self):
 | 
			
		||||
        self._completer = QMPCompleter()
 | 
			
		||||
        self._fill_completion()
 | 
			
		||||
        readline.set_completer(self._completer.complete)
 | 
			
		||||
        readline.parse_and_bind("tab: complete")
 | 
			
		||||
        # XXX: default delimiters conflict with some command names (eg. query-),
 | 
			
		||||
        # clearing everything as it doesn't seem to matter
 | 
			
		||||
        readline.set_completer_delims('')
 | 
			
		||||
 | 
			
		||||
    def __build_cmd(self, cmdline):
 | 
			
		||||
        """
 | 
			
		||||
        Build a QMP input object from a user provided command-line in the
 | 
			
		||||
        following format:
 | 
			
		||||
    
 | 
			
		||||
            < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
 | 
			
		||||
        """
 | 
			
		||||
        cmdargs = cmdline.split()
 | 
			
		||||
        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
 | 
			
		||||
        for arg in cmdargs[1:]:
 | 
			
		||||
            opt = arg.split('=')
 | 
			
		||||
            try:
 | 
			
		||||
                value = int(opt[1])
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                value = opt[1]
 | 
			
		||||
            qmpcmd['arguments'][opt[0]] = value
 | 
			
		||||
        return qmpcmd
 | 
			
		||||
 | 
			
		||||
    def _execute_cmd(self, cmdline):
 | 
			
		||||
        try:
 | 
			
		||||
            qmpcmd = self.__build_cmd(cmdline)
 | 
			
		||||
        except:
 | 
			
		||||
            print 'command format: <command-name> ',
 | 
			
		||||
            print '[arg-name1=arg1] ... [arg-nameN=argN]'
 | 
			
		||||
            return True
 | 
			
		||||
        resp = self.cmd_obj(qmpcmd)
 | 
			
		||||
        if resp is None:
 | 
			
		||||
            print 'Disconnected'
 | 
			
		||||
            return False
 | 
			
		||||
        print resp
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def connect(self):
 | 
			
		||||
        self._greeting = qmp.QEMUMonitorProtocol.connect(self)
 | 
			
		||||
        self.__completer_setup()
 | 
			
		||||
 | 
			
		||||
    def show_banner(self, msg='Welcome to the QMP low-level shell!'):
 | 
			
		||||
        print msg
 | 
			
		||||
        version = self._greeting['QMP']['version']['qemu']
 | 
			
		||||
        print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
 | 
			
		||||
 | 
			
		||||
    def read_exec_command(self, prompt):
 | 
			
		||||
        """
 | 
			
		||||
        Read and execute a command.
 | 
			
		||||
 | 
			
		||||
        @return True if execution was ok, return False if disconnected.
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            cmdline = raw_input(prompt)
 | 
			
		||||
        except EOFError:
 | 
			
		||||
            print
 | 
			
		||||
            return False
 | 
			
		||||
        if cmdline == '':
 | 
			
		||||
            for ev in self.get_events():
 | 
			
		||||
                print ev
 | 
			
		||||
            self.clear_events()
 | 
			
		||||
            return True
 | 
			
		||||
        else:
 | 
			
		||||
            return self._execute_cmd(cmdline)
 | 
			
		||||
 | 
			
		||||
class HMPShell(QMPShell):
 | 
			
		||||
    def __init__(self, address):
 | 
			
		||||
        QMPShell.__init__(self, address)
 | 
			
		||||
        self.__cpu_index = 0
 | 
			
		||||
 | 
			
		||||
    def __cmd_completion(self):
 | 
			
		||||
        for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
 | 
			
		||||
            if cmd and cmd[0] != '[' and cmd[0] != '\t':
 | 
			
		||||
                name = cmd.split()[0] # drop help text
 | 
			
		||||
                if name == 'info':
 | 
			
		||||
                    continue
 | 
			
		||||
                if name.find('|') != -1:
 | 
			
		||||
                    # Command in the form 'foobar|f' or 'f|foobar', take the
 | 
			
		||||
                    # full name
 | 
			
		||||
                    opt = name.split('|')
 | 
			
		||||
                    if len(opt[0]) == 1:
 | 
			
		||||
                        name = opt[1]
 | 
			
		||||
                    else:
 | 
			
		||||
                        name = opt[0]
 | 
			
		||||
                self._completer.append(name)
 | 
			
		||||
                self._completer.append('help ' + name) # help completion
 | 
			
		||||
 | 
			
		||||
    def __info_completion(self):
 | 
			
		||||
        for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
 | 
			
		||||
            if cmd:
 | 
			
		||||
                self._completer.append('info ' + cmd.split()[1])
 | 
			
		||||
 | 
			
		||||
    def __other_completion(self):
 | 
			
		||||
        # special cases
 | 
			
		||||
        self._completer.append('help info')
 | 
			
		||||
 | 
			
		||||
    def _fill_completion(self):
 | 
			
		||||
        self.__cmd_completion()
 | 
			
		||||
        self.__info_completion()
 | 
			
		||||
        self.__other_completion()
 | 
			
		||||
 | 
			
		||||
    def __cmd_passthrough(self, cmdline, cpu_index = 0):
 | 
			
		||||
        return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
 | 
			
		||||
                              { 'command-line': cmdline,
 | 
			
		||||
                                'cpu-index': cpu_index } })
 | 
			
		||||
 | 
			
		||||
    def _execute_cmd(self, cmdline):
 | 
			
		||||
        if cmdline.split()[0] == "cpu":
 | 
			
		||||
            # trap the cpu command, it requires special setting
 | 
			
		||||
            try:
 | 
			
		||||
                idx = int(cmdline.split()[1])
 | 
			
		||||
                if not 'return' in self.__cmd_passthrough('info version', idx):
 | 
			
		||||
                    print 'bad CPU index'
 | 
			
		||||
                    return True
 | 
			
		||||
                self.__cpu_index = idx
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                print 'cpu command takes an integer argument'
 | 
			
		||||
                return True
 | 
			
		||||
        resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
 | 
			
		||||
        if resp is None:
 | 
			
		||||
            print 'Disconnected'
 | 
			
		||||
            return False
 | 
			
		||||
        assert 'return' in resp or 'error' in resp
 | 
			
		||||
        if 'return' in resp:
 | 
			
		||||
            # Success
 | 
			
		||||
            if len(resp['return']) > 0:
 | 
			
		||||
                print resp['return'],
 | 
			
		||||
        else:
 | 
			
		||||
            # Error
 | 
			
		||||
            print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def show_banner(self):
 | 
			
		||||
        QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
 | 
			
		||||
 | 
			
		||||
def die(msg):
 | 
			
		||||
    sys.stderr.write('ERROR: %s\n' % msg)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
def fail_cmdline(option=None):
 | 
			
		||||
    if option:
 | 
			
		||||
        sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
 | 
			
		||||
    sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n')
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
def shell_help():
 | 
			
		||||
    print 'bye  exit from the shell'
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    addr = ''
 | 
			
		||||
    try:
 | 
			
		||||
        if len(sys.argv) == 2:
 | 
			
		||||
            qemu = QMPShell(sys.argv[1])
 | 
			
		||||
            addr = sys.argv[1]
 | 
			
		||||
        elif len(sys.argv) == 3:
 | 
			
		||||
            if sys.argv[1] != '-H':
 | 
			
		||||
                fail_cmdline(sys.argv[1])
 | 
			
		||||
            qemu = HMPShell(sys.argv[2])
 | 
			
		||||
            addr = sys.argv[2]
 | 
			
		||||
        else:
 | 
			
		||||
                fail_cmdline()
 | 
			
		||||
    except QMPShellBadPort:
 | 
			
		||||
        die('bad port number in command-line')
 | 
			
		||||
    if len(argv) != 2:
 | 
			
		||||
        print 'qemu-shell <unix-socket>'
 | 
			
		||||
        exit(1)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
    qemu = qmp.QEMUMonitorProtocol(argv[1])
 | 
			
		||||
    qemu.connect()
 | 
			
		||||
    except qmp.QMPConnectError:
 | 
			
		||||
        die('Didn\'t get QMP greeting message')
 | 
			
		||||
    except qmp.QMPCapabilitiesError:
 | 
			
		||||
        die('Could not negotiate capabilities')
 | 
			
		||||
    except qemu.error:
 | 
			
		||||
        die('Could not connect to %s' % addr)
 | 
			
		||||
 | 
			
		||||
    qemu.show_banner()
 | 
			
		||||
    while qemu.read_exec_command('(QEMU) '):
 | 
			
		||||
        pass
 | 
			
		||||
    qemu.close()
 | 
			
		||||
    print 'Connected!'
 | 
			
		||||
 | 
			
		||||
    while True:
 | 
			
		||||
        try:
 | 
			
		||||
            cmd = raw_input('(QEMU) ')
 | 
			
		||||
        except EOFError:
 | 
			
		||||
            print
 | 
			
		||||
            break
 | 
			
		||||
        if cmd == '':
 | 
			
		||||
            continue
 | 
			
		||||
        elif cmd == 'bye':
 | 
			
		||||
            break
 | 
			
		||||
        elif cmd == 'help':
 | 
			
		||||
            shell_help()
 | 
			
		||||
        else:
 | 
			
		||||
            try:
 | 
			
		||||
                resp = qemu.send(cmd)
 | 
			
		||||
                if resp == None:
 | 
			
		||||
                    print 'Disconnected'
 | 
			
		||||
                    break
 | 
			
		||||
                print resp
 | 
			
		||||
            except IndexError:
 | 
			
		||||
                print '-> command format: <command-name> ',
 | 
			
		||||
                print '[arg-name1=arg1] ... [arg-nameN=argN]'
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										115
									
								
								QMP/qmp-spec.txt
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								QMP/qmp-spec.txt
									
									
									
									
									
								
							@@ -44,17 +44,14 @@ they can be in ANY order, thus no particular order should be assumed.
 | 
			
		||||
 | 
			
		||||
Right when connected the Server will issue a greeting message, which signals
 | 
			
		||||
that the connection has been successfully established and that the Server is
 | 
			
		||||
ready for capabilities negotiation (for more information refer to section
 | 
			
		||||
'4. Capabilities Negotiation').
 | 
			
		||||
waiting for commands.
 | 
			
		||||
 | 
			
		||||
The format is:
 | 
			
		||||
 | 
			
		||||
{ "QMP": { "version": json-object, "capabilities": json-array } }
 | 
			
		||||
{ "QMP": { "capabilities": json-array } }
 | 
			
		||||
 | 
			
		||||
 Where,
 | 
			
		||||
 | 
			
		||||
- The "version" member contains the Server's version information (the format
 | 
			
		||||
  is the same of the 'query-version' command)
 | 
			
		||||
- The "capabilities" member specify the availability of features beyond the
 | 
			
		||||
  baseline specification
 | 
			
		||||
 | 
			
		||||
@@ -155,7 +152,7 @@ This section provides some examples of real QMP usage, in all of them
 | 
			
		||||
3.1 Server greeting
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
 | 
			
		||||
S: {"QMP": {"capabilities": []}}
 | 
			
		||||
 | 
			
		||||
3.2 Simple 'stop' execution
 | 
			
		||||
---------------------------
 | 
			
		||||
@@ -182,105 +179,25 @@ S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
 | 
			
		||||
S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
 | 
			
		||||
"POWERDOWN"}
 | 
			
		||||
 | 
			
		||||
4. Capabilities Negotiation
 | 
			
		||||
----------------------------
 | 
			
		||||
4. Compatibility Considerations
 | 
			
		||||
--------------------------------
 | 
			
		||||
 | 
			
		||||
When a Client successfully establishes a connection, the Server is in
 | 
			
		||||
Capabilities Negotiation mode.
 | 
			
		||||
In order to achieve maximum compatibility between versions, Clients must not 
 | 
			
		||||
assume any particular:
 | 
			
		||||
 | 
			
		||||
In this mode only the 'qmp_capabilities' command is allowed to run, all
 | 
			
		||||
other commands will return the CommandNotFound error. Asynchronous messages
 | 
			
		||||
are not delivered either.
 | 
			
		||||
 | 
			
		||||
Clients should use the 'qmp_capabilities' command to enable capabilities
 | 
			
		||||
advertised in the Server's greeting (section '2.2 Server Greeting') they
 | 
			
		||||
support.
 | 
			
		||||
 | 
			
		||||
When the 'qmp_capabilities' command is issued, and if it does not return an
 | 
			
		||||
error, the Server enters in Command mode where capabilities changes take
 | 
			
		||||
effect, all commands (except 'qmp_capabilities') are allowed and asynchronous
 | 
			
		||||
messages are delivered.
 | 
			
		||||
 | 
			
		||||
5 Compatibility Considerations
 | 
			
		||||
------------------------------
 | 
			
		||||
 | 
			
		||||
All protocol changes or new features which modify the protocol format in an
 | 
			
		||||
incompatible way are disabled by default and will be advertised by the
 | 
			
		||||
capabilities array (section '2.2 Server Greeting'). Thus, Clients can check
 | 
			
		||||
that array and enable the capabilities they support.
 | 
			
		||||
 | 
			
		||||
The QMP Server performs a type check on the arguments to a command.  It
 | 
			
		||||
generates an error if a value does not have the expected type for its
 | 
			
		||||
key, or if it does not understand a key that the Client included.  The
 | 
			
		||||
strictness of the Server catches wrong assumptions of Clients about
 | 
			
		||||
the Server's schema.  Clients can assume that, when such validation
 | 
			
		||||
errors occur, they will be reported before the command generated any
 | 
			
		||||
side effect.
 | 
			
		||||
 | 
			
		||||
However, Clients must not assume any particular:
 | 
			
		||||
 | 
			
		||||
- Length of json-arrays
 | 
			
		||||
- Size of json-objects; in particular, future versions of QEMU may add
 | 
			
		||||
  new keys and Clients should be able to ignore them.
 | 
			
		||||
- Size of json-objects or length of json-arrays
 | 
			
		||||
- Order of json-object members or json-array elements
 | 
			
		||||
- Amount of errors generated by a command, that is, new errors can be added
 | 
			
		||||
  to any existing command in newer versions of the Server
 | 
			
		||||
 | 
			
		||||
Of course, the Server does guarantee to send valid JSON.  But apart from
 | 
			
		||||
this, a Client should be "conservative in what they send, and liberal in
 | 
			
		||||
what they accept".
 | 
			
		||||
Additionally, Clients should always:
 | 
			
		||||
 | 
			
		||||
6. Downstream extension of QMP
 | 
			
		||||
------------------------------
 | 
			
		||||
- Check the capabilities json-array at connection time
 | 
			
		||||
- Check the availability of commands with 'query-commands' before issuing them
 | 
			
		||||
 | 
			
		||||
We recommend that downstream consumers of QEMU do *not* modify QMP.
 | 
			
		||||
Management tools should be able to support both upstream and downstream
 | 
			
		||||
versions of QMP without special logic, and downstream extensions are
 | 
			
		||||
inherently at odds with that.
 | 
			
		||||
5. Recommendations to Client implementors
 | 
			
		||||
-----------------------------------------
 | 
			
		||||
 | 
			
		||||
However, we recognize that it is sometimes impossible for downstreams to
 | 
			
		||||
avoid modifying QMP.  Both upstream and downstream need to take care to
 | 
			
		||||
preserve long-term compatibility and interoperability.
 | 
			
		||||
 | 
			
		||||
To help with that, QMP reserves JSON object member names beginning with
 | 
			
		||||
'__' (double underscore) for downstream use ("downstream names").  This
 | 
			
		||||
means upstream will never use any downstream names for its commands,
 | 
			
		||||
arguments, errors, asynchronous events, and so forth.
 | 
			
		||||
 | 
			
		||||
Any new names downstream wishes to add must begin with '__'.  To
 | 
			
		||||
ensure compatibility with other downstreams, it is strongly
 | 
			
		||||
recommended that you prefix your downstram names with '__RFQDN_' where
 | 
			
		||||
RFQDN is a valid, reverse fully qualified domain name which you
 | 
			
		||||
control.  For example, a qemu-kvm specific monitor command would be:
 | 
			
		||||
 | 
			
		||||
    (qemu) __org.linux-kvm_enable_irqchip
 | 
			
		||||
 | 
			
		||||
Downstream must not change the server greeting (section 2.2) other than
 | 
			
		||||
to offer additional capabilities.  But see below for why even that is
 | 
			
		||||
discouraged.
 | 
			
		||||
 | 
			
		||||
Section '5 Compatibility Considerations' applies to downstream as well
 | 
			
		||||
as to upstream, obviously.  It follows that downstream must behave
 | 
			
		||||
exactly like upstream for any input not containing members with
 | 
			
		||||
downstream names ("downstream members"), except it may add members
 | 
			
		||||
with downstream names to its output.
 | 
			
		||||
 | 
			
		||||
Thus, a client should not be able to distinguish downstream from
 | 
			
		||||
upstream as long as it doesn't send input with downstream members, and
 | 
			
		||||
properly ignores any downstream members in the output it receives.
 | 
			
		||||
 | 
			
		||||
Advice on downstream modifications:
 | 
			
		||||
 | 
			
		||||
1. Introducing new commands is okay.  If you want to extend an existing
 | 
			
		||||
   command, consider introducing a new one with the new behaviour
 | 
			
		||||
   instead.
 | 
			
		||||
 | 
			
		||||
2. Introducing new asynchronous messages is okay.  If you want to extend
 | 
			
		||||
   an existing message, consider adding a new one instead.
 | 
			
		||||
 | 
			
		||||
3. Introducing new errors for use in new commands is okay.  Adding new
 | 
			
		||||
   errors to existing commands counts as extension, so 1. applies.
 | 
			
		||||
 | 
			
		||||
4. New capabilities are strongly discouraged.  Capabilities are for
 | 
			
		||||
   evolving the basic protocol, and multiple diverging basic protocol
 | 
			
		||||
   dialects are most undesirable.
 | 
			
		||||
5.1 The Server should be always started in pause mode, thus the Client is
 | 
			
		||||
    able to perform any setup procedure without the risk of race conditions
 | 
			
		||||
    and related problems
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										195
									
								
								QMP/qmp.py
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								QMP/qmp.py
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
# QEMU Monitor Protocol Python class
 | 
			
		||||
# 
 | 
			
		||||
# Copyright (C) 2009, 2010 Red Hat Inc.
 | 
			
		||||
# Copyright (C) 2009 Red Hat Inc.
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Luiz Capitulino <lcapitulino@redhat.com>
 | 
			
		||||
@@ -8,9 +8,7 @@
 | 
			
		||||
# This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
			
		||||
# the COPYING file in the top-level directory.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import errno
 | 
			
		||||
import socket
 | 
			
		||||
import socket, json
 | 
			
		||||
 | 
			
		||||
class QMPError(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
@@ -18,146 +16,57 @@ class QMPError(Exception):
 | 
			
		||||
class QMPConnectError(QMPError):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class QMPCapabilitiesError(QMPError):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class QEMUMonitorProtocol:
 | 
			
		||||
    def __init__(self, address, server=False):
 | 
			
		||||
        """
 | 
			
		||||
        Create a QEMUMonitorProtocol class.
 | 
			
		||||
 | 
			
		||||
        @param address: QEMU address, can be either a unix socket path (string)
 | 
			
		||||
                        or a tuple in the form ( address, port ) for a TCP
 | 
			
		||||
                        connection
 | 
			
		||||
        @param server: server mode listens on the socket (bool)
 | 
			
		||||
        @raise socket.error on socket connection errors
 | 
			
		||||
        @note No connection is established, this is done by the connect() or
 | 
			
		||||
              accept() methods
 | 
			
		||||
        """
 | 
			
		||||
        self.__events = []
 | 
			
		||||
        self.__address = address
 | 
			
		||||
        self.__sock = self.__get_sock()
 | 
			
		||||
        if server:
 | 
			
		||||
            self.__sock.bind(self.__address)
 | 
			
		||||
            self.__sock.listen(1)
 | 
			
		||||
 | 
			
		||||
    def __get_sock(self):
 | 
			
		||||
        if isinstance(self.__address, tuple):
 | 
			
		||||
            family = socket.AF_INET
 | 
			
		||||
        else:
 | 
			
		||||
            family = socket.AF_UNIX
 | 
			
		||||
        return socket.socket(family, socket.SOCK_STREAM)
 | 
			
		||||
 | 
			
		||||
    def __negotiate_capabilities(self):
 | 
			
		||||
        self.__sockfile = self.__sock.makefile()
 | 
			
		||||
        greeting = self.__json_read()
 | 
			
		||||
        if greeting is None or not greeting.has_key('QMP'):
 | 
			
		||||
            raise QMPConnectError
 | 
			
		||||
        # Greeting seems ok, negotiate capabilities
 | 
			
		||||
        resp = self.cmd('qmp_capabilities')
 | 
			
		||||
        if "return" in resp:
 | 
			
		||||
            return greeting
 | 
			
		||||
        raise QMPCapabilitiesError
 | 
			
		||||
 | 
			
		||||
    def __json_read(self, only_event=False):
 | 
			
		||||
        while True:
 | 
			
		||||
            data = self.__sockfile.readline()
 | 
			
		||||
            if not data:
 | 
			
		||||
                return
 | 
			
		||||
            resp = json.loads(data)
 | 
			
		||||
            if 'event' in resp:
 | 
			
		||||
                self.__events.append(resp)
 | 
			
		||||
                if not only_event:
 | 
			
		||||
                    continue
 | 
			
		||||
            return resp
 | 
			
		||||
 | 
			
		||||
    error = socket.error
 | 
			
		||||
 | 
			
		||||
    def connect(self):
 | 
			
		||||
        """
 | 
			
		||||
        Connect to the QMP Monitor and perform capabilities negotiation.
 | 
			
		||||
 | 
			
		||||
        @return QMP greeting dict
 | 
			
		||||
        @raise socket.error on socket connection errors
 | 
			
		||||
        @raise QMPConnectError if the greeting is not received
 | 
			
		||||
        @raise QMPCapabilitiesError if fails to negotiate capabilities
 | 
			
		||||
        """
 | 
			
		||||
        self.__sock.connect(self.__address)
 | 
			
		||||
        return self.__negotiate_capabilities()
 | 
			
		||||
 | 
			
		||||
    def accept(self):
 | 
			
		||||
        """
 | 
			
		||||
        Await connection from QMP Monitor and perform capabilities negotiation.
 | 
			
		||||
 | 
			
		||||
        @return QMP greeting dict
 | 
			
		||||
        @raise socket.error on socket connection errors
 | 
			
		||||
        @raise QMPConnectError if the greeting is not received
 | 
			
		||||
        @raise QMPCapabilitiesError if fails to negotiate capabilities
 | 
			
		||||
        """
 | 
			
		||||
        self.__sock, _ = self.__sock.accept()
 | 
			
		||||
        return self.__negotiate_capabilities()
 | 
			
		||||
 | 
			
		||||
    def cmd_obj(self, qmp_cmd):
 | 
			
		||||
        """
 | 
			
		||||
        Send a QMP command to the QMP Monitor.
 | 
			
		||||
 | 
			
		||||
        @param qmp_cmd: QMP command to be sent as a Python dict
 | 
			
		||||
        @return QMP response as a Python dict or None if the connection has
 | 
			
		||||
                been closed
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            self.__sock.sendall(json.dumps(qmp_cmd))
 | 
			
		||||
        except socket.error, err:
 | 
			
		||||
            if err[0] == errno.EPIPE:
 | 
			
		||||
                return
 | 
			
		||||
            raise socket.error(err)
 | 
			
		||||
        return self.__json_read()
 | 
			
		||||
 | 
			
		||||
    def cmd(self, name, args=None, id=None):
 | 
			
		||||
        """
 | 
			
		||||
        Build a QMP command and send it to the QMP Monitor.
 | 
			
		||||
 | 
			
		||||
        @param name: command name (string)
 | 
			
		||||
        @param args: command arguments (dict)
 | 
			
		||||
        @param id: command id (dict, list, string or int)
 | 
			
		||||
        """
 | 
			
		||||
        qmp_cmd = { 'execute': name }
 | 
			
		||||
        if args:
 | 
			
		||||
            qmp_cmd['arguments'] = args
 | 
			
		||||
        if id:
 | 
			
		||||
            qmp_cmd['id'] = id
 | 
			
		||||
        return self.cmd_obj(qmp_cmd)
 | 
			
		||||
 | 
			
		||||
    def command(self, cmd, **kwds):
 | 
			
		||||
        ret = self.cmd(cmd, kwds)
 | 
			
		||||
        if ret.has_key('error'):
 | 
			
		||||
            raise Exception(ret['error']['desc'])
 | 
			
		||||
        return ret['return']
 | 
			
		||||
 | 
			
		||||
    def get_events(self, wait=False):
 | 
			
		||||
        """
 | 
			
		||||
        Get a list of available QMP events.
 | 
			
		||||
 | 
			
		||||
        @param wait: block until an event is available (bool)
 | 
			
		||||
        """
 | 
			
		||||
        self.__sock.setblocking(0)
 | 
			
		||||
        try:
 | 
			
		||||
            self.__json_read()
 | 
			
		||||
        except socket.error, err:
 | 
			
		||||
            if err[0] == errno.EAGAIN:
 | 
			
		||||
                # No data available
 | 
			
		||||
                pass
 | 
			
		||||
        self.__sock.setblocking(1)
 | 
			
		||||
        if not self.__events and wait:
 | 
			
		||||
            self.__json_read(only_event=True)
 | 
			
		||||
        return self.__events
 | 
			
		||||
 | 
			
		||||
    def clear_events(self):
 | 
			
		||||
        """
 | 
			
		||||
        Clear current list of pending events.
 | 
			
		||||
        """
 | 
			
		||||
        self.__events = []
 | 
			
		||||
        self.sock.connect(self.filename)
 | 
			
		||||
        data = self.__json_read()
 | 
			
		||||
        if data == None:
 | 
			
		||||
            raise QMPConnectError
 | 
			
		||||
        if not data.has_key('QMP'):
 | 
			
		||||
            raise QMPConnectError
 | 
			
		||||
        return data['QMP']['capabilities']
 | 
			
		||||
 | 
			
		||||
    def close(self):
 | 
			
		||||
        self.__sock.close()
 | 
			
		||||
        self.__sockfile.close()
 | 
			
		||||
        self.sock.close()
 | 
			
		||||
 | 
			
		||||
    def send_raw(self, line):
 | 
			
		||||
        self.sock.send(str(line))
 | 
			
		||||
        return self.__json_read()
 | 
			
		||||
 | 
			
		||||
    def send(self, cmdline):
 | 
			
		||||
        cmd = self.__build_cmd(cmdline)
 | 
			
		||||
        self.__json_send(cmd)
 | 
			
		||||
        resp = self.__json_read()
 | 
			
		||||
        if resp == None:
 | 
			
		||||
            return
 | 
			
		||||
        elif resp.has_key('error'):
 | 
			
		||||
            return resp['error']
 | 
			
		||||
        else:
 | 
			
		||||
            return resp['return']
 | 
			
		||||
 | 
			
		||||
    def __build_cmd(self, cmdline):
 | 
			
		||||
        cmdargs = cmdline.split()
 | 
			
		||||
        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
 | 
			
		||||
        for arg in cmdargs[1:]:
 | 
			
		||||
            opt = arg.split('=')
 | 
			
		||||
            try:
 | 
			
		||||
                value = int(opt[1])
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                value = opt[1]
 | 
			
		||||
            qmpcmd['arguments'][opt[0]] = value
 | 
			
		||||
        return qmpcmd
 | 
			
		||||
 | 
			
		||||
    def __json_send(self, cmd):
 | 
			
		||||
        # XXX: We have to send any additional char, otherwise
 | 
			
		||||
        # the Server won't read our input
 | 
			
		||||
        self.sock.send(json.dumps(cmd) + ' ')
 | 
			
		||||
 | 
			
		||||
    def __json_read(self):
 | 
			
		||||
        try:
 | 
			
		||||
            return json.loads(self.sock.recv(1024))
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
    def __init__(self, filename):
 | 
			
		||||
        self.filename = filename
 | 
			
		||||
        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										138
									
								
								QMP/qom-fuse
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								QMP/qom-fuse
									
									
									
									
									
								
							@@ -1,138 +0,0 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
##
 | 
			
		||||
# QEMU Object Model test tools
 | 
			
		||||
#
 | 
			
		||||
# Copyright IBM, Corp. 2012
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Anthony Liguori   <aliguori@us.ibm.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.
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
import fuse, stat
 | 
			
		||||
from fuse import Fuse
 | 
			
		||||
import os, posix
 | 
			
		||||
from errno import *
 | 
			
		||||
from qmp import QEMUMonitorProtocol
 | 
			
		||||
 | 
			
		||||
fuse.fuse_python_api = (0, 2)
 | 
			
		||||
 | 
			
		||||
class QOMFS(Fuse):
 | 
			
		||||
    def __init__(self, qmp, *args, **kwds):
 | 
			
		||||
        Fuse.__init__(self, *args, **kwds)
 | 
			
		||||
        self.qmp = qmp
 | 
			
		||||
        self.qmp.connect()
 | 
			
		||||
        self.ino_map = {}
 | 
			
		||||
        self.ino_count = 1
 | 
			
		||||
 | 
			
		||||
    def get_ino(self, path):
 | 
			
		||||
        if self.ino_map.has_key(path):
 | 
			
		||||
            return self.ino_map[path]
 | 
			
		||||
        self.ino_map[path] = self.ino_count
 | 
			
		||||
        self.ino_count += 1
 | 
			
		||||
        return self.ino_map[path]
 | 
			
		||||
 | 
			
		||||
    def is_object(self, path):
 | 
			
		||||
        try:
 | 
			
		||||
            items = self.qmp.command('qom-list', path=path)
 | 
			
		||||
            return True
 | 
			
		||||
        except:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def is_property(self, path):
 | 
			
		||||
        try:
 | 
			
		||||
            path, prop = path.rsplit('/', 1)
 | 
			
		||||
            for item in self.qmp.command('qom-list', path=path):
 | 
			
		||||
                if item['name'] == prop:
 | 
			
		||||
                    return True
 | 
			
		||||
            return False
 | 
			
		||||
        except:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def is_link(self, path):
 | 
			
		||||
        try:
 | 
			
		||||
            path, prop = path.rsplit('/', 1)
 | 
			
		||||
            for item in self.qmp.command('qom-list', path=path):
 | 
			
		||||
                if item['name'] == prop:
 | 
			
		||||
                    if item['type'].startswith('link<'):
 | 
			
		||||
                        return True
 | 
			
		||||
                    return False
 | 
			
		||||
            return False
 | 
			
		||||
        except:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def read(self, path, length, offset):
 | 
			
		||||
        if not self.is_property(path):
 | 
			
		||||
            return -ENOENT
 | 
			
		||||
 | 
			
		||||
        path, prop = path.rsplit('/', 1)
 | 
			
		||||
        try:
 | 
			
		||||
            data = str(self.qmp.command('qom-get', path=path, property=prop))
 | 
			
		||||
            data += '\n' # make values shell friendly
 | 
			
		||||
        except:
 | 
			
		||||
            return -EPERM
 | 
			
		||||
 | 
			
		||||
        if offset > len(data):
 | 
			
		||||
            return ''
 | 
			
		||||
 | 
			
		||||
        return str(data[offset:][:length])
 | 
			
		||||
 | 
			
		||||
    def readlink(self, path):
 | 
			
		||||
        if not self.is_link(path):
 | 
			
		||||
            return False
 | 
			
		||||
        path, prop = path.rsplit('/', 1)
 | 
			
		||||
        prefix = '/'.join(['..'] * (len(path.split('/')) - 1))
 | 
			
		||||
        return prefix + str(self.qmp.command('qom-get', path=path,
 | 
			
		||||
                                             property=prop))
 | 
			
		||||
 | 
			
		||||
    def getattr(self, path):
 | 
			
		||||
        if self.is_link(path):
 | 
			
		||||
            value = posix.stat_result((0755 | stat.S_IFLNK,
 | 
			
		||||
                                       self.get_ino(path),
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       2,
 | 
			
		||||
                                       1000,
 | 
			
		||||
                                       1000,
 | 
			
		||||
                                       4096,
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       0))
 | 
			
		||||
        elif self.is_object(path):
 | 
			
		||||
            value = posix.stat_result((0755 | stat.S_IFDIR,
 | 
			
		||||
                                       self.get_ino(path),
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       2,
 | 
			
		||||
                                       1000,
 | 
			
		||||
                                       1000,
 | 
			
		||||
                                       4096,
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       0))
 | 
			
		||||
        elif self.is_property(path):
 | 
			
		||||
            value = posix.stat_result((0644 | stat.S_IFREG,
 | 
			
		||||
                                       self.get_ino(path),
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       1,
 | 
			
		||||
                                       1000,
 | 
			
		||||
                                       1000,
 | 
			
		||||
                                       4096,
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       0))
 | 
			
		||||
        else:
 | 
			
		||||
            value = -ENOENT
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
    def readdir(self, path, offset):
 | 
			
		||||
        yield fuse.Direntry('.')
 | 
			
		||||
        yield fuse.Direntry('..')
 | 
			
		||||
        for item in self.qmp.command('qom-list', path=path):
 | 
			
		||||
            yield fuse.Direntry(str(item['name']))
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    import sys, os
 | 
			
		||||
 | 
			
		||||
    fs = QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET']))
 | 
			
		||||
    fs.main(sys.argv)
 | 
			
		||||
							
								
								
									
										67
									
								
								QMP/qom-get
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								QMP/qom-get
									
									
									
									
									
								
							@@ -1,67 +0,0 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
##
 | 
			
		||||
# QEMU Object Model test tools
 | 
			
		||||
#
 | 
			
		||||
# Copyright IBM, Corp. 2011
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Anthony Liguori   <aliguori@us.ibm.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.
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
from qmp import QEMUMonitorProtocol
 | 
			
		||||
 | 
			
		||||
cmd, args = sys.argv[0], sys.argv[1:]
 | 
			
		||||
socket_path = None
 | 
			
		||||
path = None
 | 
			
		||||
prop = None
 | 
			
		||||
 | 
			
		||||
def usage():
 | 
			
		||||
    return '''environment variables:
 | 
			
		||||
    QMP_SOCKET=<path | addr:port>
 | 
			
		||||
usage:
 | 
			
		||||
    %s [-h] [-s <QMP socket path | addr:port>] <path>.<property>
 | 
			
		||||
''' % cmd
 | 
			
		||||
 | 
			
		||||
def usage_error(error_msg = "unspecified error"):
 | 
			
		||||
    sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
 | 
			
		||||
    exit(1)
 | 
			
		||||
 | 
			
		||||
if len(args) > 0:
 | 
			
		||||
    if args[0] == "-h":
 | 
			
		||||
        print usage()
 | 
			
		||||
        exit(0);
 | 
			
		||||
    elif args[0] == "-s":
 | 
			
		||||
        try:
 | 
			
		||||
            socket_path = args[1]
 | 
			
		||||
        except:
 | 
			
		||||
            usage_error("missing argument: QMP socket path or address");
 | 
			
		||||
        args = args[2:]
 | 
			
		||||
 | 
			
		||||
if not socket_path:
 | 
			
		||||
    if os.environ.has_key('QMP_SOCKET'):
 | 
			
		||||
        socket_path = os.environ['QMP_SOCKET']
 | 
			
		||||
    else:
 | 
			
		||||
        usage_error("no QMP socket path or address given");
 | 
			
		||||
 | 
			
		||||
if len(args) > 0:
 | 
			
		||||
    try:
 | 
			
		||||
        path, prop = args[0].rsplit('.', 1)
 | 
			
		||||
    except:
 | 
			
		||||
        usage_error("invalid format for path/property/value")
 | 
			
		||||
else:
 | 
			
		||||
    usage_error("not enough arguments")
 | 
			
		||||
 | 
			
		||||
srv = QEMUMonitorProtocol(socket_path)
 | 
			
		||||
srv.connect()
 | 
			
		||||
 | 
			
		||||
rsp = srv.command('qom-get', path=path, property=prop)
 | 
			
		||||
if type(rsp) == dict:
 | 
			
		||||
    for i in rsp.keys():
 | 
			
		||||
        print '%s: %s' % (i, rsp[i])
 | 
			
		||||
else:
 | 
			
		||||
    print rsp
 | 
			
		||||
							
								
								
									
										64
									
								
								QMP/qom-list
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								QMP/qom-list
									
									
									
									
									
								
							@@ -1,64 +0,0 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
##
 | 
			
		||||
# QEMU Object Model test tools
 | 
			
		||||
#
 | 
			
		||||
# Copyright IBM, Corp. 2011
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Anthony Liguori   <aliguori@us.ibm.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.
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
from qmp import QEMUMonitorProtocol
 | 
			
		||||
 | 
			
		||||
cmd, args = sys.argv[0], sys.argv[1:]
 | 
			
		||||
socket_path = None
 | 
			
		||||
path = None
 | 
			
		||||
prop = None
 | 
			
		||||
 | 
			
		||||
def usage():
 | 
			
		||||
    return '''environment variables:
 | 
			
		||||
    QMP_SOCKET=<path | addr:port>
 | 
			
		||||
usage:
 | 
			
		||||
    %s [-h] [-s <QMP socket path | addr:port>] [<path>]
 | 
			
		||||
''' % cmd
 | 
			
		||||
 | 
			
		||||
def usage_error(error_msg = "unspecified error"):
 | 
			
		||||
    sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
 | 
			
		||||
    exit(1)
 | 
			
		||||
 | 
			
		||||
if len(args) > 0:
 | 
			
		||||
    if args[0] == "-h":
 | 
			
		||||
        print usage()
 | 
			
		||||
        exit(0);
 | 
			
		||||
    elif args[0] == "-s":
 | 
			
		||||
        try:
 | 
			
		||||
            socket_path = args[1]
 | 
			
		||||
        except:
 | 
			
		||||
            usage_error("missing argument: QMP socket path or address");
 | 
			
		||||
        args = args[2:]
 | 
			
		||||
 | 
			
		||||
if not socket_path:
 | 
			
		||||
    if os.environ.has_key('QMP_SOCKET'):
 | 
			
		||||
        socket_path = os.environ['QMP_SOCKET']
 | 
			
		||||
    else:
 | 
			
		||||
        usage_error("no QMP socket path or address given");
 | 
			
		||||
 | 
			
		||||
srv = QEMUMonitorProtocol(socket_path)
 | 
			
		||||
srv.connect()
 | 
			
		||||
 | 
			
		||||
if len(args) == 0:
 | 
			
		||||
    print '/'
 | 
			
		||||
    sys.exit(0)
 | 
			
		||||
 | 
			
		||||
for item in srv.command('qom-list', path=args[0]):
 | 
			
		||||
    if item['type'].startswith('child<'):
 | 
			
		||||
        print '%s/' % item['name']
 | 
			
		||||
    elif item['type'].startswith('link<'):
 | 
			
		||||
        print '@%s/' % item['name']
 | 
			
		||||
    else:
 | 
			
		||||
        print '%s' % item['name']
 | 
			
		||||
							
								
								
									
										64
									
								
								QMP/qom-set
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								QMP/qom-set
									
									
									
									
									
								
							@@ -1,64 +0,0 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
##
 | 
			
		||||
# QEMU Object Model test tools
 | 
			
		||||
#
 | 
			
		||||
# Copyright IBM, Corp. 2011
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Anthony Liguori   <aliguori@us.ibm.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.
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
from qmp import QEMUMonitorProtocol
 | 
			
		||||
 | 
			
		||||
cmd, args = sys.argv[0], sys.argv[1:]
 | 
			
		||||
socket_path = None
 | 
			
		||||
path = None
 | 
			
		||||
prop = None
 | 
			
		||||
value = None
 | 
			
		||||
 | 
			
		||||
def usage():
 | 
			
		||||
    return '''environment variables:
 | 
			
		||||
    QMP_SOCKET=<path | addr:port>
 | 
			
		||||
usage:
 | 
			
		||||
    %s [-h] [-s <QMP socket path | addr:port>] <path>.<property> <value>
 | 
			
		||||
''' % cmd
 | 
			
		||||
 | 
			
		||||
def usage_error(error_msg = "unspecified error"):
 | 
			
		||||
    sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
 | 
			
		||||
    exit(1)
 | 
			
		||||
 | 
			
		||||
if len(args) > 0:
 | 
			
		||||
    if args[0] == "-h":
 | 
			
		||||
        print usage()
 | 
			
		||||
        exit(0);
 | 
			
		||||
    elif args[0] == "-s":
 | 
			
		||||
        try:
 | 
			
		||||
            socket_path = args[1]
 | 
			
		||||
        except:
 | 
			
		||||
            usage_error("missing argument: QMP socket path or address");
 | 
			
		||||
        args = args[2:]
 | 
			
		||||
 | 
			
		||||
if not socket_path:
 | 
			
		||||
    if os.environ.has_key('QMP_SOCKET'):
 | 
			
		||||
        socket_path = os.environ['QMP_SOCKET']
 | 
			
		||||
    else:
 | 
			
		||||
        usage_error("no QMP socket path or address given");
 | 
			
		||||
 | 
			
		||||
if len(args) > 1:
 | 
			
		||||
    try:
 | 
			
		||||
        path, prop = args[0].rsplit('.', 1)
 | 
			
		||||
    except:
 | 
			
		||||
        usage_error("invalid format for path/property/value")
 | 
			
		||||
    value = args[1]
 | 
			
		||||
else:
 | 
			
		||||
    usage_error("not enough arguments")
 | 
			
		||||
 | 
			
		||||
srv = QEMUMonitorProtocol(socket_path)
 | 
			
		||||
srv.connect()
 | 
			
		||||
 | 
			
		||||
print srv.command('qom-set', path=path, property=prop, value=sys.argv[2])
 | 
			
		||||
							
								
								
									
										32
									
								
								QMP/vm-info
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								QMP/vm-info
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
#!/usr/bin/python
 | 
			
		||||
#
 | 
			
		||||
# Print Virtual Machine information
 | 
			
		||||
#
 | 
			
		||||
# Usage:
 | 
			
		||||
#
 | 
			
		||||
# Start QEMU with:
 | 
			
		||||
#
 | 
			
		||||
# $ qemu [...] -monitor control,unix:./qmp,server
 | 
			
		||||
#
 | 
			
		||||
# Run vm-info:
 | 
			
		||||
#
 | 
			
		||||
# $ vm-info ./qmp
 | 
			
		||||
#
 | 
			
		||||
# Luiz Capitulino <lcapitulino@redhat.com>
 | 
			
		||||
 | 
			
		||||
import qmp
 | 
			
		||||
from sys import argv,exit
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    if len(argv) != 2:
 | 
			
		||||
        print 'vm-info <unix-socket>'
 | 
			
		||||
        exit(1)
 | 
			
		||||
 | 
			
		||||
    qemu = qmp.QEMUMonitorProtocol(argv[1])
 | 
			
		||||
    qemu.connect()
 | 
			
		||||
 | 
			
		||||
    for cmd in [ 'version', 'hpet', 'kvm', 'status', 'uuid', 'balloon' ]:
 | 
			
		||||
        print cmd + ': ' + str(qemu.send('query-' + cmd))
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										4
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								README
									
									
									
									
									
								
							@@ -1,3 +1,3 @@
 | 
			
		||||
Read the documentation in qemu-doc.html or on http://wiki.qemu.org
 | 
			
		||||
Read the documentation in qemu-doc.html.
 | 
			
		||||
 | 
			
		||||
- QEMU team
 | 
			
		||||
Fabrice Bellard.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								a.out.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								a.out.h
									
									
									
									
									
								
							@@ -151,7 +151,7 @@ struct external_lineno {
 | 
			
		||||
#define E_FILNMLEN	14	/* # characters in a file name		*/
 | 
			
		||||
#define E_DIMNUM	4	/* # array dimensions in auxiliary entry */
 | 
			
		||||
 | 
			
		||||
struct QEMU_PACKED external_syment
 | 
			
		||||
struct __attribute__((packed)) external_syment
 | 
			
		||||
{
 | 
			
		||||
  union {
 | 
			
		||||
    char e_name[E_SYMNMLEN];
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								acl.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								acl.c
									
									
									
									
									
								
							@@ -24,6 +24,7 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "sysemu.h"
 | 
			
		||||
#include "acl.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_FNMATCH
 | 
			
		||||
@@ -55,8 +56,8 @@ qemu_acl *qemu_acl_init(const char *aclname)
 | 
			
		||||
    if (acl)
 | 
			
		||||
        return acl;
 | 
			
		||||
 | 
			
		||||
    acl = g_malloc(sizeof(*acl));
 | 
			
		||||
    acl->aclname = g_strdup(aclname);
 | 
			
		||||
    acl = qemu_malloc(sizeof(*acl));
 | 
			
		||||
    acl->aclname = qemu_strdup(aclname);
 | 
			
		||||
    /* Deny by default, so there is no window of "open
 | 
			
		||||
     * access" between QEMU starting, and the user setting
 | 
			
		||||
     * up ACLs in the monitor */
 | 
			
		||||
@@ -65,7 +66,7 @@ qemu_acl *qemu_acl_init(const char *aclname)
 | 
			
		||||
    acl->nentries = 0;
 | 
			
		||||
    QTAILQ_INIT(&acl->entries);
 | 
			
		||||
 | 
			
		||||
    acls = g_realloc(acls, sizeof(*acls) * (nacls +1));
 | 
			
		||||
    acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1));
 | 
			
		||||
    acls[nacls] = acl;
 | 
			
		||||
    nacls++;
 | 
			
		||||
 | 
			
		||||
@@ -95,13 +96,13 @@ int qemu_acl_party_is_allowed(qemu_acl *acl,
 | 
			
		||||
 | 
			
		||||
void qemu_acl_reset(qemu_acl *acl)
 | 
			
		||||
{
 | 
			
		||||
    qemu_acl_entry *entry, *next_entry;
 | 
			
		||||
    qemu_acl_entry *entry;
 | 
			
		||||
 | 
			
		||||
    /* Put back to deny by default, so there is no window
 | 
			
		||||
     * of "open access" while the user re-initializes the
 | 
			
		||||
     * access control list */
 | 
			
		||||
    acl->defaultDeny = 1;
 | 
			
		||||
    QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) {
 | 
			
		||||
    QTAILQ_FOREACH(entry, &acl->entries, next) {
 | 
			
		||||
        QTAILQ_REMOVE(&acl->entries, entry, next);
 | 
			
		||||
        free(entry->match);
 | 
			
		||||
        free(entry);
 | 
			
		||||
@@ -116,8 +117,8 @@ int qemu_acl_append(qemu_acl *acl,
 | 
			
		||||
{
 | 
			
		||||
    qemu_acl_entry *entry;
 | 
			
		||||
 | 
			
		||||
    entry = g_malloc(sizeof(*entry));
 | 
			
		||||
    entry->match = g_strdup(match);
 | 
			
		||||
    entry = qemu_malloc(sizeof(*entry));
 | 
			
		||||
    entry->match = qemu_strdup(match);
 | 
			
		||||
    entry->deny = deny;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_INSERT_TAIL(&acl->entries, entry, next);
 | 
			
		||||
@@ -142,8 +143,8 @@ int qemu_acl_insert(qemu_acl *acl,
 | 
			
		||||
        return qemu_acl_append(acl, deny, match);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    entry = g_malloc(sizeof(*entry));
 | 
			
		||||
    entry->match = g_strdup(match);
 | 
			
		||||
    entry = qemu_malloc(sizeof(*entry));
 | 
			
		||||
    entry->match = qemu_strdup(match);
 | 
			
		||||
    entry->deny = deny;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(tmp, &acl->entries, next) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										88
									
								
								aio.c
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								aio.c
									
									
									
									
									
								
							@@ -9,8 +9,6 @@
 | 
			
		||||
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
			
		||||
 * the COPYING file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributions after 2012-01-13 are licensed under the terms of the
 | 
			
		||||
 * GNU GPL, version 2 or (at your option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
@@ -35,6 +33,7 @@ struct AioHandler
 | 
			
		||||
    IOHandler *io_read;
 | 
			
		||||
    IOHandler *io_write;
 | 
			
		||||
    AioFlushHandler *io_flush;
 | 
			
		||||
    AioProcessQueue *io_process_queue;
 | 
			
		||||
    int deleted;
 | 
			
		||||
    void *opaque;
 | 
			
		||||
    QLIST_ENTRY(AioHandler) node;
 | 
			
		||||
@@ -57,6 +56,7 @@ int qemu_aio_set_fd_handler(int fd,
 | 
			
		||||
                            IOHandler *io_read,
 | 
			
		||||
                            IOHandler *io_write,
 | 
			
		||||
                            AioFlushHandler *io_flush,
 | 
			
		||||
                            AioProcessQueue *io_process_queue,
 | 
			
		||||
                            void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    AioHandler *node;
 | 
			
		||||
@@ -75,13 +75,13 @@ int qemu_aio_set_fd_handler(int fd,
 | 
			
		||||
                 * releasing the walking_handlers lock.
 | 
			
		||||
                 */
 | 
			
		||||
                QLIST_REMOVE(node, node);
 | 
			
		||||
                g_free(node);
 | 
			
		||||
                qemu_free(node);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (node == NULL) {
 | 
			
		||||
            /* Alloc and insert if it's not already there */
 | 
			
		||||
            node = g_malloc0(sizeof(AioHandler));
 | 
			
		||||
            node = qemu_mallocz(sizeof(AioHandler));
 | 
			
		||||
            node->fd = fd;
 | 
			
		||||
            QLIST_INSERT_HEAD(&aio_handlers, node, node);
 | 
			
		||||
        }
 | 
			
		||||
@@ -89,6 +89,7 @@ int qemu_aio_set_fd_handler(int fd,
 | 
			
		||||
        node->io_read = io_read;
 | 
			
		||||
        node->io_write = io_write;
 | 
			
		||||
        node->io_flush = io_flush;
 | 
			
		||||
        node->io_process_queue = io_process_queue;
 | 
			
		||||
        node->opaque = opaque;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -99,25 +100,64 @@ int qemu_aio_set_fd_handler(int fd,
 | 
			
		||||
 | 
			
		||||
void qemu_aio_flush(void)
 | 
			
		||||
{
 | 
			
		||||
    while (qemu_aio_wait());
 | 
			
		||||
    AioHandler *node;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        ret = 0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If there are pending emulated aio start them now so flush
 | 
			
		||||
	 * will be able to return 1.
 | 
			
		||||
	 */
 | 
			
		||||
        qemu_aio_wait();
 | 
			
		||||
 | 
			
		||||
        QLIST_FOREACH(node, &aio_handlers, node) {
 | 
			
		||||
            if (node->io_flush) {
 | 
			
		||||
                ret |= node->io_flush(node->opaque);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } while (qemu_bh_poll() || ret > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool qemu_aio_wait(void)
 | 
			
		||||
int qemu_aio_process_queue(void)
 | 
			
		||||
{
 | 
			
		||||
    AioHandler *node;
 | 
			
		||||
    fd_set rdfds, wrfds;
 | 
			
		||||
    int max_fd = -1;
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
 | 
			
		||||
    walking_handlers = 1;
 | 
			
		||||
 | 
			
		||||
    QLIST_FOREACH(node, &aio_handlers, node) {
 | 
			
		||||
        if (node->io_process_queue) {
 | 
			
		||||
            if (node->io_process_queue(node->opaque)) {
 | 
			
		||||
                ret = 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    walking_handlers = 0;
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_aio_wait(void)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    bool busy;
 | 
			
		||||
 | 
			
		||||
    if (qemu_bh_poll())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * If there are callbacks left that have been queued, we need to call then.
 | 
			
		||||
     * Do not call select in this case, because it is possible that the caller
 | 
			
		||||
     * does not need a complete flush (as is the case for qemu_aio_wait loops).
 | 
			
		||||
     * Return afterwards to avoid waiting needlessly in select().
 | 
			
		||||
     */
 | 
			
		||||
    if (qemu_bh_poll()) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (qemu_aio_process_queue())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        AioHandler *node;
 | 
			
		||||
        fd_set rdfds, wrfds;
 | 
			
		||||
        int max_fd = -1;
 | 
			
		||||
 | 
			
		||||
        walking_handlers = 1;
 | 
			
		||||
 | 
			
		||||
@@ -125,18 +165,14 @@ bool qemu_aio_wait(void)
 | 
			
		||||
        FD_ZERO(&wrfds);
 | 
			
		||||
 | 
			
		||||
        /* fill fd sets */
 | 
			
		||||
    busy = false;
 | 
			
		||||
        QLIST_FOREACH(node, &aio_handlers, node) {
 | 
			
		||||
            /* If there aren't pending AIO operations, don't invoke callbacks.
 | 
			
		||||
             * Otherwise, if there are no AIO requests, qemu_aio_wait() would
 | 
			
		||||
             * wait indefinitely.
 | 
			
		||||
             */
 | 
			
		||||
        if (node->io_flush) {
 | 
			
		||||
            if (node->io_flush(node->opaque) == 0) {
 | 
			
		||||
            if (node->io_flush && node->io_flush(node->opaque) == 0)
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            busy = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            if (!node->deleted && node->io_read) {
 | 
			
		||||
                FD_SET(node->fd, &rdfds);
 | 
			
		||||
                max_fd = MAX(max_fd, node->fd + 1);
 | 
			
		||||
@@ -150,12 +186,13 @@ bool qemu_aio_wait(void)
 | 
			
		||||
        walking_handlers = 0;
 | 
			
		||||
 | 
			
		||||
        /* No AIO operations?  Get us out of here */
 | 
			
		||||
    if (!busy) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
        if (max_fd == -1)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        /* wait until next event */
 | 
			
		||||
        ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
 | 
			
		||||
        if (ret == -1 && errno == EINTR)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        /* if we have any readable fds, dispatch event */
 | 
			
		||||
        if (ret > 0) {
 | 
			
		||||
@@ -183,12 +220,11 @@ bool qemu_aio_wait(void)
 | 
			
		||||
 | 
			
		||||
                if (tmp->deleted) {
 | 
			
		||||
                    QLIST_REMOVE(tmp, node);
 | 
			
		||||
                g_free(tmp);
 | 
			
		||||
                    qemu_free(tmp);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            walking_handlers = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
    } while (ret == 0);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,9 +22,6 @@ along with this file; see the file COPYING.  If not, see
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include "dis-asm.h"
 | 
			
		||||
 | 
			
		||||
/* MAX is redefined below, so remove any previous definition. */
 | 
			
		||||
#undef MAX
 | 
			
		||||
 | 
			
		||||
/* The opcode table is an array of struct alpha_opcode.  */
 | 
			
		||||
 | 
			
		||||
struct alpha_opcode
 | 
			
		||||
@@ -238,6 +235,10 @@ extern const unsigned alpha_num_operands;
 | 
			
		||||
#define AXP_REG_SP	30
 | 
			
		||||
#define AXP_REG_ZERO	31
 | 
			
		||||
 | 
			
		||||
#define bfd_mach_alpha_ev4  0x10
 | 
			
		||||
#define bfd_mach_alpha_ev5  0x20
 | 
			
		||||
#define bfd_mach_alpha_ev6  0x30
 | 
			
		||||
 | 
			
		||||
enum bfd_reloc_code_real {
 | 
			
		||||
    BFD_RELOC_23_PCREL_S2,
 | 
			
		||||
    BFD_RELOC_ALPHA_HINT
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										732
									
								
								arch_init.c
									
									
									
									
									
								
							
							
						
						
									
										732
									
								
								arch_init.c
									
									
									
									
									
								
							@@ -1,732 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU System Emulator
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2003-2008 Fabrice Bellard
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "monitor.h"
 | 
			
		||||
#include "sysemu.h"
 | 
			
		||||
#include "arch_init.h"
 | 
			
		||||
#include "audio/audio.h"
 | 
			
		||||
#include "hw/pc.h"
 | 
			
		||||
#include "hw/pci.h"
 | 
			
		||||
#include "hw/audiodev.h"
 | 
			
		||||
#include "kvm.h"
 | 
			
		||||
#include "migration.h"
 | 
			
		||||
#include "net.h"
 | 
			
		||||
#include "gdbstub.h"
 | 
			
		||||
#include "hw/smbios.h"
 | 
			
		||||
#include "exec-memory.h"
 | 
			
		||||
#include "hw/pcspk.h"
 | 
			
		||||
 | 
			
		||||
#ifdef TARGET_SPARC
 | 
			
		||||
int graphic_width = 1024;
 | 
			
		||||
int graphic_height = 768;
 | 
			
		||||
int graphic_depth = 8;
 | 
			
		||||
#else
 | 
			
		||||
int graphic_width = 800;
 | 
			
		||||
int graphic_height = 600;
 | 
			
		||||
int graphic_depth = 15;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf";
 | 
			
		||||
 | 
			
		||||
#if defined(TARGET_ALPHA)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_ALPHA
 | 
			
		||||
#elif defined(TARGET_ARM)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_ARM
 | 
			
		||||
#elif defined(TARGET_CRIS)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_CRIS
 | 
			
		||||
#elif defined(TARGET_I386)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_I386
 | 
			
		||||
#elif defined(TARGET_M68K)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_M68K
 | 
			
		||||
#elif defined(TARGET_LM32)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_LM32
 | 
			
		||||
#elif defined(TARGET_MICROBLAZE)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
 | 
			
		||||
#elif defined(TARGET_MIPS)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_MIPS
 | 
			
		||||
#elif defined(TARGET_PPC)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_PPC
 | 
			
		||||
#elif defined(TARGET_S390X)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_S390X
 | 
			
		||||
#elif defined(TARGET_SH4)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_SH4
 | 
			
		||||
#elif defined(TARGET_SPARC)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_SPARC
 | 
			
		||||
#elif defined(TARGET_XTENSA)
 | 
			
		||||
#define QEMU_ARCH QEMU_ARCH_XTENSA
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const uint32_t arch_type = QEMU_ARCH;
 | 
			
		||||
 | 
			
		||||
/***********************************************************/
 | 
			
		||||
/* ram save/restore */
 | 
			
		||||
 | 
			
		||||
#define RAM_SAVE_FLAG_FULL     0x01 /* Obsolete, not used anymore */
 | 
			
		||||
#define RAM_SAVE_FLAG_COMPRESS 0x02
 | 
			
		||||
#define RAM_SAVE_FLAG_MEM_SIZE 0x04
 | 
			
		||||
#define RAM_SAVE_FLAG_PAGE     0x08
 | 
			
		||||
#define RAM_SAVE_FLAG_EOS      0x10
 | 
			
		||||
#define RAM_SAVE_FLAG_CONTINUE 0x20
 | 
			
		||||
 | 
			
		||||
#ifdef __ALTIVEC__
 | 
			
		||||
#include <altivec.h>
 | 
			
		||||
#define VECTYPE        vector unsigned char
 | 
			
		||||
#define SPLAT(p)       vec_splat(vec_ld(0, p), 0)
 | 
			
		||||
#define ALL_EQ(v1, v2) vec_all_eq(v1, v2)
 | 
			
		||||
#elif defined __SSE2__
 | 
			
		||||
#include <emmintrin.h>
 | 
			
		||||
#define VECTYPE        __m128i
 | 
			
		||||
#define SPLAT(p)       _mm_set1_epi8(*(p))
 | 
			
		||||
#define ALL_EQ(v1, v2) (_mm_movemask_epi8(_mm_cmpeq_epi8(v1, v2)) == 0xFFFF)
 | 
			
		||||
#else
 | 
			
		||||
#define VECTYPE        unsigned long
 | 
			
		||||
#define SPLAT(p)       (*(p) * (~0UL / 255))
 | 
			
		||||
#define ALL_EQ(v1, v2) ((v1) == (v2))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int is_dup_page(uint8_t *page)
 | 
			
		||||
{
 | 
			
		||||
    VECTYPE *p = (VECTYPE *)page;
 | 
			
		||||
    VECTYPE val = SPLAT(page);
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < TARGET_PAGE_SIZE / sizeof(VECTYPE); i++) {
 | 
			
		||||
        if (!ALL_EQ(val, p[i])) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static RAMBlock *last_block;
 | 
			
		||||
static ram_addr_t last_offset;
 | 
			
		||||
 | 
			
		||||
static int ram_save_block(QEMUFile *f)
 | 
			
		||||
{
 | 
			
		||||
    RAMBlock *block = last_block;
 | 
			
		||||
    ram_addr_t offset = last_offset;
 | 
			
		||||
    int bytes_sent = 0;
 | 
			
		||||
    MemoryRegion *mr;
 | 
			
		||||
 | 
			
		||||
    if (!block)
 | 
			
		||||
        block = QLIST_FIRST(&ram_list.blocks);
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        mr = block->mr;
 | 
			
		||||
        if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
 | 
			
		||||
                                    DIRTY_MEMORY_MIGRATION)) {
 | 
			
		||||
            uint8_t *p;
 | 
			
		||||
            int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
 | 
			
		||||
 | 
			
		||||
            memory_region_reset_dirty(mr, offset, TARGET_PAGE_SIZE,
 | 
			
		||||
                                      DIRTY_MEMORY_MIGRATION);
 | 
			
		||||
 | 
			
		||||
            p = memory_region_get_ram_ptr(mr) + offset;
 | 
			
		||||
 | 
			
		||||
            if (is_dup_page(p)) {
 | 
			
		||||
                qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_COMPRESS);
 | 
			
		||||
                if (!cont) {
 | 
			
		||||
                    qemu_put_byte(f, strlen(block->idstr));
 | 
			
		||||
                    qemu_put_buffer(f, (uint8_t *)block->idstr,
 | 
			
		||||
                                    strlen(block->idstr));
 | 
			
		||||
                }
 | 
			
		||||
                qemu_put_byte(f, *p);
 | 
			
		||||
                bytes_sent = 1;
 | 
			
		||||
            } else {
 | 
			
		||||
                qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_PAGE);
 | 
			
		||||
                if (!cont) {
 | 
			
		||||
                    qemu_put_byte(f, strlen(block->idstr));
 | 
			
		||||
                    qemu_put_buffer(f, (uint8_t *)block->idstr,
 | 
			
		||||
                                    strlen(block->idstr));
 | 
			
		||||
                }
 | 
			
		||||
                qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
 | 
			
		||||
                bytes_sent = TARGET_PAGE_SIZE;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        offset += TARGET_PAGE_SIZE;
 | 
			
		||||
        if (offset >= block->length) {
 | 
			
		||||
            offset = 0;
 | 
			
		||||
            block = QLIST_NEXT(block, next);
 | 
			
		||||
            if (!block)
 | 
			
		||||
                block = QLIST_FIRST(&ram_list.blocks);
 | 
			
		||||
        }
 | 
			
		||||
    } while (block != last_block || offset != last_offset);
 | 
			
		||||
 | 
			
		||||
    last_block = block;
 | 
			
		||||
    last_offset = offset;
 | 
			
		||||
 | 
			
		||||
    return bytes_sent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint64_t bytes_transferred;
 | 
			
		||||
 | 
			
		||||
static ram_addr_t ram_save_remaining(void)
 | 
			
		||||
{
 | 
			
		||||
    RAMBlock *block;
 | 
			
		||||
    ram_addr_t count = 0;
 | 
			
		||||
 | 
			
		||||
    QLIST_FOREACH(block, &ram_list.blocks, next) {
 | 
			
		||||
        ram_addr_t addr;
 | 
			
		||||
        for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
 | 
			
		||||
            if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
 | 
			
		||||
                                        DIRTY_MEMORY_MIGRATION)) {
 | 
			
		||||
                count++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t ram_bytes_remaining(void)
 | 
			
		||||
{
 | 
			
		||||
    return ram_save_remaining() * TARGET_PAGE_SIZE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t ram_bytes_transferred(void)
 | 
			
		||||
{
 | 
			
		||||
    return bytes_transferred;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t ram_bytes_total(void)
 | 
			
		||||
{
 | 
			
		||||
    RAMBlock *block;
 | 
			
		||||
    uint64_t total = 0;
 | 
			
		||||
 | 
			
		||||
    QLIST_FOREACH(block, &ram_list.blocks, next)
 | 
			
		||||
        total += block->length;
 | 
			
		||||
 | 
			
		||||
    return total;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int block_compar(const void *a, const void *b)
 | 
			
		||||
{
 | 
			
		||||
    RAMBlock * const *ablock = a;
 | 
			
		||||
    RAMBlock * const *bblock = b;
 | 
			
		||||
 | 
			
		||||
    return strcmp((*ablock)->idstr, (*bblock)->idstr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sort_ram_list(void)
 | 
			
		||||
{
 | 
			
		||||
    RAMBlock *block, *nblock, **blocks;
 | 
			
		||||
    int n;
 | 
			
		||||
    n = 0;
 | 
			
		||||
    QLIST_FOREACH(block, &ram_list.blocks, next) {
 | 
			
		||||
        ++n;
 | 
			
		||||
    }
 | 
			
		||||
    blocks = g_malloc(n * sizeof *blocks);
 | 
			
		||||
    n = 0;
 | 
			
		||||
    QLIST_FOREACH_SAFE(block, &ram_list.blocks, next, nblock) {
 | 
			
		||||
        blocks[n++] = block;
 | 
			
		||||
        QLIST_REMOVE(block, next);
 | 
			
		||||
    }
 | 
			
		||||
    qsort(blocks, n, sizeof *blocks, block_compar);
 | 
			
		||||
    while (--n >= 0) {
 | 
			
		||||
        QLIST_INSERT_HEAD(&ram_list.blocks, blocks[n], next);
 | 
			
		||||
    }
 | 
			
		||||
    g_free(blocks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ram_save_live(QEMUFile *f, int stage, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    ram_addr_t addr;
 | 
			
		||||
    uint64_t bytes_transferred_last;
 | 
			
		||||
    double bwidth = 0;
 | 
			
		||||
    uint64_t expected_time = 0;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (stage < 0) {
 | 
			
		||||
        memory_global_dirty_log_stop();
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memory_global_sync_dirty_bitmap(get_system_memory());
 | 
			
		||||
 | 
			
		||||
    if (stage == 1) {
 | 
			
		||||
        RAMBlock *block;
 | 
			
		||||
        bytes_transferred = 0;
 | 
			
		||||
        last_block = NULL;
 | 
			
		||||
        last_offset = 0;
 | 
			
		||||
        sort_ram_list();
 | 
			
		||||
 | 
			
		||||
        /* Make sure all dirty bits are set */
 | 
			
		||||
        QLIST_FOREACH(block, &ram_list.blocks, next) {
 | 
			
		||||
            for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
 | 
			
		||||
                if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
 | 
			
		||||
                                             DIRTY_MEMORY_MIGRATION)) {
 | 
			
		||||
                    memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        memory_global_dirty_log_start();
 | 
			
		||||
 | 
			
		||||
        qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
 | 
			
		||||
 | 
			
		||||
        QLIST_FOREACH(block, &ram_list.blocks, next) {
 | 
			
		||||
            qemu_put_byte(f, strlen(block->idstr));
 | 
			
		||||
            qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
 | 
			
		||||
            qemu_put_be64(f, block->length);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bytes_transferred_last = bytes_transferred;
 | 
			
		||||
    bwidth = qemu_get_clock_ns(rt_clock);
 | 
			
		||||
 | 
			
		||||
    while ((ret = qemu_file_rate_limit(f)) == 0) {
 | 
			
		||||
        int bytes_sent;
 | 
			
		||||
 | 
			
		||||
        bytes_sent = ram_save_block(f);
 | 
			
		||||
        bytes_transferred += bytes_sent;
 | 
			
		||||
        if (bytes_sent == 0) { /* no more blocks */
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
 | 
			
		||||
    bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
 | 
			
		||||
 | 
			
		||||
    /* if we haven't transferred anything this round, force expected_time to a
 | 
			
		||||
     * a very high value, but without crashing */
 | 
			
		||||
    if (bwidth == 0) {
 | 
			
		||||
        bwidth = 0.000001;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* try transferring iterative blocks of memory */
 | 
			
		||||
    if (stage == 3) {
 | 
			
		||||
        int bytes_sent;
 | 
			
		||||
 | 
			
		||||
        /* flush all remaining blocks regardless of rate limiting */
 | 
			
		||||
        while ((bytes_sent = ram_save_block(f)) != 0) {
 | 
			
		||||
            bytes_transferred += bytes_sent;
 | 
			
		||||
        }
 | 
			
		||||
        memory_global_dirty_log_stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
 | 
			
		||||
 | 
			
		||||
    expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
 | 
			
		||||
 | 
			
		||||
    return (stage == 2) && (expected_time <= migrate_max_downtime());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *host_from_stream_offset(QEMUFile *f,
 | 
			
		||||
                                            ram_addr_t offset,
 | 
			
		||||
                                            int flags)
 | 
			
		||||
{
 | 
			
		||||
    static RAMBlock *block = NULL;
 | 
			
		||||
    char id[256];
 | 
			
		||||
    uint8_t len;
 | 
			
		||||
 | 
			
		||||
    if (flags & RAM_SAVE_FLAG_CONTINUE) {
 | 
			
		||||
        if (!block) {
 | 
			
		||||
            fprintf(stderr, "Ack, bad migration stream!\n");
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return memory_region_get_ram_ptr(block->mr) + offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    len = qemu_get_byte(f);
 | 
			
		||||
    qemu_get_buffer(f, (uint8_t *)id, len);
 | 
			
		||||
    id[len] = 0;
 | 
			
		||||
 | 
			
		||||
    QLIST_FOREACH(block, &ram_list.blocks, next) {
 | 
			
		||||
        if (!strncmp(id, block->idstr, sizeof(id)))
 | 
			
		||||
            return memory_region_get_ram_ptr(block->mr) + offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fprintf(stderr, "Can't find block %s!\n", id);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ram_load(QEMUFile *f, void *opaque, int version_id)
 | 
			
		||||
{
 | 
			
		||||
    ram_addr_t addr;
 | 
			
		||||
    int flags;
 | 
			
		||||
    int error;
 | 
			
		||||
 | 
			
		||||
    if (version_id < 4 || version_id > 4) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        addr = qemu_get_be64(f);
 | 
			
		||||
 | 
			
		||||
        flags = addr & ~TARGET_PAGE_MASK;
 | 
			
		||||
        addr &= TARGET_PAGE_MASK;
 | 
			
		||||
 | 
			
		||||
        if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
 | 
			
		||||
            if (version_id == 4) {
 | 
			
		||||
                /* Synchronize RAM block list */
 | 
			
		||||
                char id[256];
 | 
			
		||||
                ram_addr_t length;
 | 
			
		||||
                ram_addr_t total_ram_bytes = addr;
 | 
			
		||||
 | 
			
		||||
                while (total_ram_bytes) {
 | 
			
		||||
                    RAMBlock *block;
 | 
			
		||||
                    uint8_t len;
 | 
			
		||||
 | 
			
		||||
                    len = qemu_get_byte(f);
 | 
			
		||||
                    qemu_get_buffer(f, (uint8_t *)id, len);
 | 
			
		||||
                    id[len] = 0;
 | 
			
		||||
                    length = qemu_get_be64(f);
 | 
			
		||||
 | 
			
		||||
                    QLIST_FOREACH(block, &ram_list.blocks, next) {
 | 
			
		||||
                        if (!strncmp(id, block->idstr, sizeof(id))) {
 | 
			
		||||
                            if (block->length != length)
 | 
			
		||||
                                return -EINVAL;
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (!block) {
 | 
			
		||||
                        fprintf(stderr, "Unknown ramblock \"%s\", cannot "
 | 
			
		||||
                                "accept migration\n", id);
 | 
			
		||||
                        return -EINVAL;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    total_ram_bytes -= length;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (flags & RAM_SAVE_FLAG_COMPRESS) {
 | 
			
		||||
            void *host;
 | 
			
		||||
            uint8_t ch;
 | 
			
		||||
 | 
			
		||||
            host = host_from_stream_offset(f, addr, flags);
 | 
			
		||||
            if (!host) {
 | 
			
		||||
                return -EINVAL;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ch = qemu_get_byte(f);
 | 
			
		||||
            memset(host, ch, TARGET_PAGE_SIZE);
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
            if (ch == 0 &&
 | 
			
		||||
                (!kvm_enabled() || kvm_has_sync_mmu())) {
 | 
			
		||||
                qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
        } else if (flags & RAM_SAVE_FLAG_PAGE) {
 | 
			
		||||
            void *host;
 | 
			
		||||
 | 
			
		||||
            host = host_from_stream_offset(f, addr, flags);
 | 
			
		||||
 | 
			
		||||
            qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
 | 
			
		||||
        }
 | 
			
		||||
        error = qemu_file_get_error(f);
 | 
			
		||||
        if (error) {
 | 
			
		||||
            return error;
 | 
			
		||||
        }
 | 
			
		||||
    } while (!(flags & RAM_SAVE_FLAG_EOS));
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAS_AUDIO
 | 
			
		||||
struct soundhw {
 | 
			
		||||
    const char *name;
 | 
			
		||||
    const char *descr;
 | 
			
		||||
    int enabled;
 | 
			
		||||
    int isa;
 | 
			
		||||
    union {
 | 
			
		||||
        int (*init_isa) (ISABus *bus);
 | 
			
		||||
        int (*init_pci) (PCIBus *bus);
 | 
			
		||||
    } init;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct soundhw soundhw[] = {
 | 
			
		||||
#ifdef HAS_AUDIO_CHOICE
 | 
			
		||||
#ifdef CONFIG_PCSPK
 | 
			
		||||
    {
 | 
			
		||||
        "pcspk",
 | 
			
		||||
        "PC speaker",
 | 
			
		||||
        0,
 | 
			
		||||
        1,
 | 
			
		||||
        { .init_isa = pcspk_audio_init }
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_SB16
 | 
			
		||||
    {
 | 
			
		||||
        "sb16",
 | 
			
		||||
        "Creative Sound Blaster 16",
 | 
			
		||||
        0,
 | 
			
		||||
        1,
 | 
			
		||||
        { .init_isa = SB16_init }
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_CS4231A
 | 
			
		||||
    {
 | 
			
		||||
        "cs4231a",
 | 
			
		||||
        "CS4231A",
 | 
			
		||||
        0,
 | 
			
		||||
        1,
 | 
			
		||||
        { .init_isa = cs4231a_init }
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ADLIB
 | 
			
		||||
    {
 | 
			
		||||
        "adlib",
 | 
			
		||||
#ifdef HAS_YMF262
 | 
			
		||||
        "Yamaha YMF262 (OPL3)",
 | 
			
		||||
#else
 | 
			
		||||
        "Yamaha YM3812 (OPL2)",
 | 
			
		||||
#endif
 | 
			
		||||
        0,
 | 
			
		||||
        1,
 | 
			
		||||
        { .init_isa = Adlib_init }
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_GUS
 | 
			
		||||
    {
 | 
			
		||||
        "gus",
 | 
			
		||||
        "Gravis Ultrasound GF1",
 | 
			
		||||
        0,
 | 
			
		||||
        1,
 | 
			
		||||
        { .init_isa = GUS_init }
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_AC97
 | 
			
		||||
    {
 | 
			
		||||
        "ac97",
 | 
			
		||||
        "Intel 82801AA AC97 Audio",
 | 
			
		||||
        0,
 | 
			
		||||
        0,
 | 
			
		||||
        { .init_pci = ac97_init }
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ES1370
 | 
			
		||||
    {
 | 
			
		||||
        "es1370",
 | 
			
		||||
        "ENSONIQ AudioPCI ES1370",
 | 
			
		||||
        0,
 | 
			
		||||
        0,
 | 
			
		||||
        { .init_pci = es1370_init }
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_HDA
 | 
			
		||||
    {
 | 
			
		||||
        "hda",
 | 
			
		||||
        "Intel HD Audio",
 | 
			
		||||
        0,
 | 
			
		||||
        0,
 | 
			
		||||
        { .init_pci = intel_hda_and_codec_init }
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* HAS_AUDIO_CHOICE */
 | 
			
		||||
 | 
			
		||||
    { NULL, NULL, 0, 0, { NULL } }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void select_soundhw(const char *optarg)
 | 
			
		||||
{
 | 
			
		||||
    struct soundhw *c;
 | 
			
		||||
 | 
			
		||||
    if (*optarg == '?') {
 | 
			
		||||
    show_valid_cards:
 | 
			
		||||
 | 
			
		||||
        printf("Valid sound card names (comma separated):\n");
 | 
			
		||||
        for (c = soundhw; c->name; ++c) {
 | 
			
		||||
            printf ("%-11s %s\n", c->name, c->descr);
 | 
			
		||||
        }
 | 
			
		||||
        printf("\n-soundhw all will enable all of the above\n");
 | 
			
		||||
        exit(*optarg != '?');
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        size_t l;
 | 
			
		||||
        const char *p;
 | 
			
		||||
        char *e;
 | 
			
		||||
        int bad_card = 0;
 | 
			
		||||
 | 
			
		||||
        if (!strcmp(optarg, "all")) {
 | 
			
		||||
            for (c = soundhw; c->name; ++c) {
 | 
			
		||||
                c->enabled = 1;
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        p = optarg;
 | 
			
		||||
        while (*p) {
 | 
			
		||||
            e = strchr(p, ',');
 | 
			
		||||
            l = !e ? strlen(p) : (size_t) (e - p);
 | 
			
		||||
 | 
			
		||||
            for (c = soundhw; c->name; ++c) {
 | 
			
		||||
                if (!strncmp(c->name, p, l) && !c->name[l]) {
 | 
			
		||||
                    c->enabled = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!c->name) {
 | 
			
		||||
                if (l > 80) {
 | 
			
		||||
                    fprintf(stderr,
 | 
			
		||||
                            "Unknown sound card name (too big to show)\n");
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    fprintf(stderr, "Unknown sound card name `%.*s'\n",
 | 
			
		||||
                            (int) l, p);
 | 
			
		||||
                }
 | 
			
		||||
                bad_card = 1;
 | 
			
		||||
            }
 | 
			
		||||
            p += l + (e != NULL);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (bad_card) {
 | 
			
		||||
            goto show_valid_cards;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_init(ISABus *isa_bus, PCIBus *pci_bus)
 | 
			
		||||
{
 | 
			
		||||
    struct soundhw *c;
 | 
			
		||||
 | 
			
		||||
    for (c = soundhw; c->name; ++c) {
 | 
			
		||||
        if (c->enabled) {
 | 
			
		||||
            if (c->isa) {
 | 
			
		||||
                if (isa_bus) {
 | 
			
		||||
                    c->init.init_isa(isa_bus);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if (pci_bus) {
 | 
			
		||||
                    c->init.init_pci(pci_bus);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
void select_soundhw(const char *optarg)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
void audio_init(ISABus *isa_bus, PCIBus *pci_bus)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int qemu_uuid_parse(const char *str, uint8_t *uuid)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (strlen(str) != 36) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3],
 | 
			
		||||
                 &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9],
 | 
			
		||||
                 &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14],
 | 
			
		||||
                 &uuid[15]);
 | 
			
		||||
 | 
			
		||||
    if (ret != 16) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef TARGET_I386
 | 
			
		||||
    smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid);
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void do_acpitable_option(const char *optarg)
 | 
			
		||||
{
 | 
			
		||||
#ifdef TARGET_I386
 | 
			
		||||
    if (acpi_table_add(optarg) < 0) {
 | 
			
		||||
        fprintf(stderr, "Wrong acpi table provided\n");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void do_smbios_option(const char *optarg)
 | 
			
		||||
{
 | 
			
		||||
#ifdef TARGET_I386
 | 
			
		||||
    if (smbios_entry_add(optarg) < 0) {
 | 
			
		||||
        fprintf(stderr, "Wrong smbios provided\n");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpudef_init(void)
 | 
			
		||||
{
 | 
			
		||||
#if defined(cpudef_setup)
 | 
			
		||||
    cpudef_setup(); /* parse cpu definitions in target config file */
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int audio_available(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAS_AUDIO
 | 
			
		||||
    return 1;
 | 
			
		||||
#else
 | 
			
		||||
    return 0;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int tcg_available(void)
 | 
			
		||||
{
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int kvm_available(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_KVM
 | 
			
		||||
    return 1;
 | 
			
		||||
#else
 | 
			
		||||
    return 0;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int xen_available(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_XEN
 | 
			
		||||
    return 1;
 | 
			
		||||
#else
 | 
			
		||||
    return 0;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								arch_init.h
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								arch_init.h
									
									
									
									
									
								
							@@ -1,35 +0,0 @@
 | 
			
		||||
#ifndef QEMU_ARCH_INIT_H
 | 
			
		||||
#define QEMU_ARCH_INIT_H
 | 
			
		||||
 | 
			
		||||
extern const char arch_config_name[];
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    QEMU_ARCH_ALL = -1,
 | 
			
		||||
    QEMU_ARCH_ALPHA = 1,
 | 
			
		||||
    QEMU_ARCH_ARM = 2,
 | 
			
		||||
    QEMU_ARCH_CRIS = 4,
 | 
			
		||||
    QEMU_ARCH_I386 = 8,
 | 
			
		||||
    QEMU_ARCH_M68K = 16,
 | 
			
		||||
    QEMU_ARCH_LM32 = 32,
 | 
			
		||||
    QEMU_ARCH_MICROBLAZE = 64,
 | 
			
		||||
    QEMU_ARCH_MIPS = 128,
 | 
			
		||||
    QEMU_ARCH_PPC = 256,
 | 
			
		||||
    QEMU_ARCH_S390X = 512,
 | 
			
		||||
    QEMU_ARCH_SH4 = 1024,
 | 
			
		||||
    QEMU_ARCH_SPARC = 2048,
 | 
			
		||||
    QEMU_ARCH_XTENSA = 4096,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const uint32_t arch_type;
 | 
			
		||||
 | 
			
		||||
void select_soundhw(const char *optarg);
 | 
			
		||||
void do_acpitable_option(const char *optarg);
 | 
			
		||||
void do_smbios_option(const char *optarg);
 | 
			
		||||
void cpudef_init(void);
 | 
			
		||||
int audio_available(void);
 | 
			
		||||
void audio_init(ISABus *isa_bus, PCIBus *pci_bus);
 | 
			
		||||
int tcg_available(void);
 | 
			
		||||
int kvm_available(void);
 | 
			
		||||
int xen_available(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										61
									
								
								arm-dis.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								arm-dis.c
									
									
									
									
									
								
							@@ -60,8 +60,10 @@
 | 
			
		||||
#define FPU_VFP_EXT_V3	 0
 | 
			
		||||
#define FPU_NEON_EXT_V1	 0
 | 
			
		||||
 | 
			
		||||
int floatformat_ieee_single_little;
 | 
			
		||||
/* Assume host uses ieee float.  */
 | 
			
		||||
static void floatformat_to_double (unsigned char *data, double *dest)
 | 
			
		||||
static void floatformat_to_double (int *ignored, unsigned char *data,
 | 
			
		||||
                                   double *dest)
 | 
			
		||||
{
 | 
			
		||||
    union {
 | 
			
		||||
        uint32_t i;
 | 
			
		||||
@@ -1587,7 +1589,7 @@ arm_decode_bitfield (const char *ptr, unsigned long insn,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
arm_decode_shift (long given, fprintf_function func, void *stream,
 | 
			
		||||
arm_decode_shift (long given, fprintf_ftype func, void *stream,
 | 
			
		||||
		  int print_shift)
 | 
			
		||||
{
 | 
			
		||||
  func (stream, "%s", arm_regnames[given & 0xf]);
 | 
			
		||||
@@ -1624,7 +1626,7 @@ arm_decode_shift (long given, fprintf_function func, void *stream,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Print one coprocessor instruction on INFO->STREAM.
 | 
			
		||||
   Return true if the instruction matched, false if this is not a
 | 
			
		||||
   Return true if the instuction matched, false if this is not a
 | 
			
		||||
   recognised coprocessor instruction.  */
 | 
			
		||||
 | 
			
		||||
static bfd_boolean
 | 
			
		||||
@@ -1633,7 +1635,7 @@ print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given,
 | 
			
		||||
{
 | 
			
		||||
  const struct opcode32 *insn;
 | 
			
		||||
  void *stream = info->stream;
 | 
			
		||||
  fprintf_function func = info->fprintf_func;
 | 
			
		||||
  fprintf_ftype func = info->fprintf_func;
 | 
			
		||||
  unsigned long mask;
 | 
			
		||||
  unsigned long value;
 | 
			
		||||
  int cond;
 | 
			
		||||
@@ -2127,7 +2129,7 @@ static void
 | 
			
		||||
print_arm_address (bfd_vma pc, struct disassemble_info *info, long given)
 | 
			
		||||
{
 | 
			
		||||
  void *stream = info->stream;
 | 
			
		||||
  fprintf_function func = info->fprintf_func;
 | 
			
		||||
  fprintf_ftype func = info->fprintf_func;
 | 
			
		||||
 | 
			
		||||
  if (((given & 0x000f0000) == 0x000f0000)
 | 
			
		||||
      && ((given & 0x02000000) == 0))
 | 
			
		||||
@@ -2214,7 +2216,7 @@ print_arm_address (bfd_vma pc, struct disassemble_info *info, long given)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Print one neon instruction on INFO->STREAM.
 | 
			
		||||
   Return true if the instruction matched, false if this is not a
 | 
			
		||||
   Return true if the instuction matched, false if this is not a
 | 
			
		||||
   recognised neon instruction.  */
 | 
			
		||||
 | 
			
		||||
static bfd_boolean
 | 
			
		||||
@@ -2222,7 +2224,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
 | 
			
		||||
{
 | 
			
		||||
  const struct opcode32 *insn;
 | 
			
		||||
  void *stream = info->stream;
 | 
			
		||||
  fprintf_function func = info->fprintf_func;
 | 
			
		||||
  fprintf_ftype func = info->fprintf_func;
 | 
			
		||||
 | 
			
		||||
  if (thumb)
 | 
			
		||||
    {
 | 
			
		||||
@@ -2515,6 +2517,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
 | 
			
		||||
			  {
 | 
			
		||||
			    func (stream, "<illegal constant %.8x:%x:%x>",
 | 
			
		||||
                                  bits, cmode, op);
 | 
			
		||||
                            size = 32;
 | 
			
		||||
			    break;
 | 
			
		||||
			  }
 | 
			
		||||
                        switch (size)
 | 
			
		||||
@@ -2540,7 +2543,9 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
 | 
			
		||||
                                valbytes[2] = (value >> 16) & 0xff;
 | 
			
		||||
                                valbytes[3] = (value >> 24) & 0xff;
 | 
			
		||||
 | 
			
		||||
                                floatformat_to_double (valbytes, &fvalue);
 | 
			
		||||
                                floatformat_to_double
 | 
			
		||||
                                  (&floatformat_ieee_single_little, valbytes,
 | 
			
		||||
                                  &fvalue);
 | 
			
		||||
 | 
			
		||||
                                func (stream, "#%.7g\t; 0x%.8lx", fvalue,
 | 
			
		||||
                                      value);
 | 
			
		||||
@@ -2676,7 +2681,7 @@ print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given)
 | 
			
		||||
{
 | 
			
		||||
  const struct opcode32 *insn;
 | 
			
		||||
  void *stream = info->stream;
 | 
			
		||||
  fprintf_function func = info->fprintf_func;
 | 
			
		||||
  fprintf_ftype func = info->fprintf_func;
 | 
			
		||||
 | 
			
		||||
  if (print_insn_coprocessor (pc, info, given, false))
 | 
			
		||||
    return;
 | 
			
		||||
@@ -3036,7 +3041,7 @@ print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
			
		||||
{
 | 
			
		||||
  const struct opcode16 *insn;
 | 
			
		||||
  void *stream = info->stream;
 | 
			
		||||
  fprintf_function func = info->fprintf_func;
 | 
			
		||||
  fprintf_ftype func = info->fprintf_func;
 | 
			
		||||
 | 
			
		||||
  for (insn = thumb_opcodes; insn->assembler; insn++)
 | 
			
		||||
    if ((given & insn->mask) == insn->value)
 | 
			
		||||
@@ -3148,14 +3153,14 @@ print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
			
		||||
		      if (started)
 | 
			
		||||
			func (stream, ", ");
 | 
			
		||||
		      started = 1;
 | 
			
		||||
		      func (stream, "%s", arm_regnames[14] /* "lr" */);
 | 
			
		||||
		      func (stream, arm_regnames[14] /* "lr" */);
 | 
			
		||||
		    }
 | 
			
		||||
 | 
			
		||||
		  if (domaskpc)
 | 
			
		||||
		    {
 | 
			
		||||
		      if (started)
 | 
			
		||||
			func (stream, ", ");
 | 
			
		||||
		      func (stream, "%s", arm_regnames[15] /* "pc" */);
 | 
			
		||||
		      func (stream, arm_regnames[15] /* "pc" */);
 | 
			
		||||
		    }
 | 
			
		||||
 | 
			
		||||
		  func (stream, "}");
 | 
			
		||||
@@ -3312,7 +3317,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
			
		||||
{
 | 
			
		||||
  const struct opcode32 *insn;
 | 
			
		||||
  void *stream = info->stream;
 | 
			
		||||
  fprintf_function func = info->fprintf_func;
 | 
			
		||||
  fprintf_ftype func = info->fprintf_func;
 | 
			
		||||
 | 
			
		||||
  if (print_insn_coprocessor (pc, info, given, true))
 | 
			
		||||
    return;
 | 
			
		||||
@@ -3698,7 +3703,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
			
		||||
		  }
 | 
			
		||||
		else
 | 
			
		||||
		  {
 | 
			
		||||
		    func (stream, "%s", psr_name (given & 0xff));
 | 
			
		||||
		    func (stream, psr_name (given & 0xff));
 | 
			
		||||
		  }
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
@@ -3706,7 +3711,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
			
		||||
		if ((given & 0xff) == 0)
 | 
			
		||||
		  func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C');
 | 
			
		||||
		else
 | 
			
		||||
		  func (stream, "%s", psr_name (given & 0xff));
 | 
			
		||||
		  func (stream, psr_name (given & 0xff));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	      case '0': case '1': case '2': case '3': case '4':
 | 
			
		||||
@@ -3927,7 +3932,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
 | 
			
		||||
	    n = last_mapping_sym - 1;
 | 
			
		||||
 | 
			
		||||
	  /* No mapping symbol found at this address.  Look backwards
 | 
			
		||||
	     for a preceding one.  */
 | 
			
		||||
	     for a preceeding one.  */
 | 
			
		||||
	  for (; n >= 0; n--)
 | 
			
		||||
	    {
 | 
			
		||||
	      if (get_sym_code_type (info, n, &type))
 | 
			
		||||
@@ -4101,30 +4106,6 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
 | 
			
		||||
       addresses, since the addend is not currently pc-relative.  */
 | 
			
		||||
    pc = 0;
 | 
			
		||||
 | 
			
		||||
  /* We include the hexdump of the instruction. The format here
 | 
			
		||||
     matches that used by objdump and the ARM ARM (in particular,
 | 
			
		||||
     32 bit Thumb instructions are displayed as pairs of halfwords,
 | 
			
		||||
     not as a single word.)  */
 | 
			
		||||
  if (is_thumb)
 | 
			
		||||
    {
 | 
			
		||||
      if (size == 2)
 | 
			
		||||
	{
 | 
			
		||||
	  info->fprintf_func(info->stream, "%04lx       ",
 | 
			
		||||
			     ((unsigned long)given) & 0xffff);
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  info->fprintf_func(info->stream, "%04lx %04lx  ",
 | 
			
		||||
			     (((unsigned long)given) >> 16) & 0xffff,
 | 
			
		||||
			     ((unsigned long)given) & 0xffff);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      info->fprintf_func(info->stream, "%08lx      ",
 | 
			
		||||
			 ((unsigned long)given) & 0xffffffff);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  printer (pc, info, given);
 | 
			
		||||
 | 
			
		||||
  if (is_thumb)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										123
									
								
								arm-semi.c
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								arm-semi.c
									
									
									
									
									
								
							@@ -33,8 +33,8 @@
 | 
			
		||||
#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
 | 
			
		||||
#else
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "sysemu.h"
 | 
			
		||||
#include "gdbstub.h"
 | 
			
		||||
#include "hw/arm-misc.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SYS_OPEN        0x01
 | 
			
		||||
@@ -108,7 +108,7 @@ static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
 | 
			
		||||
    return code;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
 | 
			
		||||
static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
 | 
			
		||||
{
 | 
			
		||||
    return code;
 | 
			
		||||
}
 | 
			
		||||
@@ -122,7 +122,7 @@ static target_ulong arm_semi_syscall_len;
 | 
			
		||||
static target_ulong syscall_err;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void arm_semi_cb(CPUARMState *env, target_ulong ret, target_ulong err)
 | 
			
		||||
static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_USER_ONLY
 | 
			
		||||
    TaskState *ts = env->opaque;
 | 
			
		||||
@@ -152,7 +152,7 @@ static void arm_semi_cb(CPUARMState *env, target_ulong ret, target_ulong err)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void arm_semi_flen_cb(CPUARMState *env, target_ulong ret, target_ulong err)
 | 
			
		||||
static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err)
 | 
			
		||||
{
 | 
			
		||||
    /* The size is always stored in big-endian order, extract
 | 
			
		||||
       the value. We assume the size always fit in 32 bits.  */
 | 
			
		||||
@@ -174,7 +174,7 @@ static void arm_semi_flen_cb(CPUARMState *env, target_ulong ret, target_ulong er
 | 
			
		||||
    __arg;					\
 | 
			
		||||
})
 | 
			
		||||
#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
 | 
			
		||||
uint32_t do_arm_semihosting(CPUARMState *env)
 | 
			
		||||
uint32_t do_arm_semihosting(CPUState *env)
 | 
			
		||||
{
 | 
			
		||||
    target_ulong args;
 | 
			
		||||
    char * s;
 | 
			
		||||
@@ -184,7 +184,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
			
		||||
#ifdef CONFIG_USER_ONLY
 | 
			
		||||
    TaskState *ts = env->opaque;
 | 
			
		||||
#else
 | 
			
		||||
    CPUARMState *ts = env;
 | 
			
		||||
    CPUState *ts = env;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    nr = env->regs[0];
 | 
			
		||||
@@ -370,88 +370,49 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
			
		||||
        return syscall_err;
 | 
			
		||||
#endif
 | 
			
		||||
    case SYS_GET_CMDLINE:
 | 
			
		||||
#ifdef CONFIG_USER_ONLY
 | 
			
		||||
        /* Build a commandline from the original argv.  */
 | 
			
		||||
        {
 | 
			
		||||
            /* Build a command-line from the original argv.
 | 
			
		||||
             *
 | 
			
		||||
             * The inputs are:
 | 
			
		||||
             *     * ARG(0), pointer to a buffer of at least the size
 | 
			
		||||
             *               specified in ARG(1).
 | 
			
		||||
             *     * ARG(1), size of the buffer pointed to by ARG(0) in
 | 
			
		||||
             *               bytes.
 | 
			
		||||
             *
 | 
			
		||||
             * The outputs are:
 | 
			
		||||
             *     * ARG(0), pointer to null-terminated string of the
 | 
			
		||||
             *               command line.
 | 
			
		||||
             *     * ARG(1), length of the string pointed to by ARG(0).
 | 
			
		||||
             */
 | 
			
		||||
            char **arg = ts->info->host_argv;
 | 
			
		||||
            int len = ARG(1);
 | 
			
		||||
            /* lock the buffer on the ARM side */
 | 
			
		||||
            char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
 | 
			
		||||
 | 
			
		||||
            char *output_buffer;
 | 
			
		||||
            size_t input_size = ARG(1);
 | 
			
		||||
            size_t output_size;
 | 
			
		||||
            int status = 0;
 | 
			
		||||
            if (!cmdline_buffer)
 | 
			
		||||
                /* FIXME - should this error code be -TARGET_EFAULT ? */
 | 
			
		||||
                return (uint32_t)-1;
 | 
			
		||||
 | 
			
		||||
            /* Compute the size of the output string.  */
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
            output_size = strlen(ts->boot_info->kernel_filename)
 | 
			
		||||
                        + 1  /* Separating space.  */
 | 
			
		||||
                        + strlen(ts->boot_info->kernel_cmdline)
 | 
			
		||||
                        + 1; /* Terminating null byte.  */
 | 
			
		||||
#else
 | 
			
		||||
            unsigned int i;
 | 
			
		||||
            s = cmdline_buffer;
 | 
			
		||||
            while (*arg && len > 2) {
 | 
			
		||||
                int n = strlen(*arg);
 | 
			
		||||
 | 
			
		||||
            output_size = ts->info->arg_end - ts->info->arg_start;
 | 
			
		||||
            if (!output_size) {
 | 
			
		||||
                /* We special-case the "empty command line" case (argc==0).
 | 
			
		||||
                   Just provide the terminating 0. */
 | 
			
		||||
                output_size = 1;
 | 
			
		||||
                if (s != cmdline_buffer) {
 | 
			
		||||
                    *(s++) = ' ';
 | 
			
		||||
                    len--;
 | 
			
		||||
                }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            if (output_size > input_size) {
 | 
			
		||||
                 /* Not enough space to store command-line arguments.  */
 | 
			
		||||
                return -1;
 | 
			
		||||
                if (n >= len)
 | 
			
		||||
                    n = len - 1;
 | 
			
		||||
                memcpy(s, *arg, n);
 | 
			
		||||
                s += n;
 | 
			
		||||
                len -= n;
 | 
			
		||||
                arg++;
 | 
			
		||||
            }
 | 
			
		||||
            /* Null terminate the string.  */
 | 
			
		||||
            *s = 0;
 | 
			
		||||
            len = s - cmdline_buffer;
 | 
			
		||||
 | 
			
		||||
            /* Adjust the command-line length.  */
 | 
			
		||||
            SET_ARG(1, output_size - 1);
 | 
			
		||||
 | 
			
		||||
            /* Lock the buffer on the ARM side.  */
 | 
			
		||||
            output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0);
 | 
			
		||||
            if (!output_buffer) {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Copy the command-line arguments.  */
 | 
			
		||||
#if !defined(CONFIG_USER_ONLY)
 | 
			
		||||
            pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename);
 | 
			
		||||
            pstrcat(output_buffer, output_size, " ");
 | 
			
		||||
            pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline);
 | 
			
		||||
#else
 | 
			
		||||
            if (output_size == 1) {
 | 
			
		||||
                /* Empty command-line.  */
 | 
			
		||||
                output_buffer[0] = '\0';
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (copy_from_user(output_buffer, ts->info->arg_start,
 | 
			
		||||
                               output_size)) {
 | 
			
		||||
                status = -1;
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Separate arguments by white spaces.  */
 | 
			
		||||
            for (i = 0; i < output_size - 1; i++) {
 | 
			
		||||
                if (output_buffer[i] == 0) {
 | 
			
		||||
                    output_buffer[i] = ' ';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        out:
 | 
			
		||||
#endif
 | 
			
		||||
            /* Unlock the buffer on the ARM side.  */
 | 
			
		||||
            unlock_user(output_buffer, ARG(0), output_size);
 | 
			
		||||
            unlock_user(cmdline_buffer, ARG(0), len);
 | 
			
		||||
 | 
			
		||||
            return status;
 | 
			
		||||
            /* Adjust the commandline length argument.  */
 | 
			
		||||
            SET_ARG(1, len);
 | 
			
		||||
 | 
			
		||||
            /* Return success if commandline fit into buffer.  */
 | 
			
		||||
            return *arg ? -1 : 0;
 | 
			
		||||
        }
 | 
			
		||||
#else
 | 
			
		||||
      return -1;
 | 
			
		||||
#endif
 | 
			
		||||
    case SYS_HEAPINFO:
 | 
			
		||||
        {
 | 
			
		||||
            uint32_t *ptr;
 | 
			
		||||
@@ -461,16 +422,15 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
			
		||||
            /* Some C libraries assume the heap immediately follows .bss, so
 | 
			
		||||
               allocate it using sbrk.  */
 | 
			
		||||
            if (!ts->heap_limit) {
 | 
			
		||||
                abi_ulong ret;
 | 
			
		||||
                long ret;
 | 
			
		||||
 | 
			
		||||
                ts->heap_base = do_brk(0);
 | 
			
		||||
                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
 | 
			
		||||
                /* Try a big heap, and reduce the size if that fails.  */
 | 
			
		||||
                for (;;) {
 | 
			
		||||
                    ret = do_brk(limit);
 | 
			
		||||
                    if (ret >= limit) {
 | 
			
		||||
                    if (ret != -1)
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    limit = (ts->heap_base >> 1) + (limit >> 1);
 | 
			
		||||
                }
 | 
			
		||||
                ts->heap_limit = limit;
 | 
			
		||||
@@ -499,7 +459,6 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    case SYS_EXIT:
 | 
			
		||||
        gdb_exit(env, 0);
 | 
			
		||||
        exit(0);
 | 
			
		||||
    default:
 | 
			
		||||
        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								arm.ld
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								arm.ld
									
									
									
									
									
								
							@@ -71,23 +71,23 @@ SECTIONS
 | 
			
		||||
  .data1   : { *(.data1) }
 | 
			
		||||
  .preinit_array     :
 | 
			
		||||
  {
 | 
			
		||||
    PROVIDE (__preinit_array_start = .);
 | 
			
		||||
    PROVIDE_HIDDEN (__preinit_array_start = .);
 | 
			
		||||
    KEEP (*(.preinit_array))
 | 
			
		||||
    PROVIDE (__preinit_array_end = .);
 | 
			
		||||
    PROVIDE_HIDDEN (__preinit_array_end = .);
 | 
			
		||||
  }
 | 
			
		||||
  .init_array     :
 | 
			
		||||
  {
 | 
			
		||||
     PROVIDE (__init_array_start = .);
 | 
			
		||||
     PROVIDE_HIDDEN (__init_array_start = .);
 | 
			
		||||
     KEEP (*(SORT(.init_array.*)))
 | 
			
		||||
     KEEP (*(.init_array))
 | 
			
		||||
     PROVIDE (__init_array_end = .);
 | 
			
		||||
     PROVIDE_HIDDEN (__init_array_end = .);
 | 
			
		||||
  }
 | 
			
		||||
  .fini_array     :
 | 
			
		||||
  {
 | 
			
		||||
    PROVIDE (__fini_array_start = .);
 | 
			
		||||
    PROVIDE_HIDDEN (__fini_array_start = .);
 | 
			
		||||
    KEEP (*(.fini_array))
 | 
			
		||||
    KEEP (*(SORT(.fini_array.*)))
 | 
			
		||||
    PROVIDE (__fini_array_end = .);
 | 
			
		||||
    PROVIDE_HIDDEN (__fini_array_end = .);
 | 
			
		||||
  }
 | 
			
		||||
  .ctors         :
 | 
			
		||||
  {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										124
									
								
								async.c
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								async.c
									
									
									
									
									
								
							@@ -24,10 +24,93 @@
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "qemu-aio.h"
 | 
			
		||||
#include "main-loop.h"
 | 
			
		||||
 | 
			
		||||
/* Anchor of the list of Bottom Halves belonging to the context */
 | 
			
		||||
static struct QEMUBH *first_bh;
 | 
			
		||||
/*
 | 
			
		||||
 * An AsyncContext protects the callbacks of AIO requests and Bottom Halves
 | 
			
		||||
 * against interfering with each other. A typical example is qcow2 that accepts
 | 
			
		||||
 * asynchronous requests, but relies for manipulation of its metadata on
 | 
			
		||||
 * synchronous bdrv_read/write that doesn't trigger any callbacks.
 | 
			
		||||
 *
 | 
			
		||||
 * However, these functions are often emulated using AIO which means that AIO
 | 
			
		||||
 * callbacks must be run - but at the same time we must not run callbacks of
 | 
			
		||||
 * other requests as they might start to modify metadata and corrupt the
 | 
			
		||||
 * internal state of the caller of bdrv_read/write.
 | 
			
		||||
 *
 | 
			
		||||
 * To achieve the desired semantics we switch into a new AsyncContext.
 | 
			
		||||
 * Callbacks must only be run if they belong to the current AsyncContext.
 | 
			
		||||
 * Otherwise they need to be queued until their own context is active again.
 | 
			
		||||
 * This is how you can make qemu_aio_wait() wait only for your own callbacks.
 | 
			
		||||
 *
 | 
			
		||||
 * The AsyncContexts form a stack. When you leave a AsyncContexts, you always
 | 
			
		||||
 * return to the old ("parent") context.
 | 
			
		||||
 */
 | 
			
		||||
struct AsyncContext {
 | 
			
		||||
    /* Consecutive number of the AsyncContext (position in the stack) */
 | 
			
		||||
    int id;
 | 
			
		||||
 | 
			
		||||
    /* Anchor of the list of Bottom Halves belonging to the context */
 | 
			
		||||
    struct QEMUBH *first_bh;
 | 
			
		||||
 | 
			
		||||
    /* Link to parent context */
 | 
			
		||||
    struct AsyncContext *parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* The currently active AsyncContext */
 | 
			
		||||
static struct AsyncContext *async_context = &(struct AsyncContext) { 0 };
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Enter a new AsyncContext. Already scheduled Bottom Halves and AIO callbacks
 | 
			
		||||
 * won't be called until this context is left again.
 | 
			
		||||
 */
 | 
			
		||||
void async_context_push(void)
 | 
			
		||||
{
 | 
			
		||||
    struct AsyncContext *new = qemu_mallocz(sizeof(*new));
 | 
			
		||||
    new->parent = async_context;
 | 
			
		||||
    new->id = async_context->id + 1;
 | 
			
		||||
    async_context = new;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Run queued AIO completions and destroy Bottom Half */
 | 
			
		||||
static void bh_run_aio_completions(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    QEMUBH **bh = opaque;
 | 
			
		||||
    qemu_bh_delete(*bh);
 | 
			
		||||
    qemu_free(bh);
 | 
			
		||||
    qemu_aio_process_queue();
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
 * Leave the currently active AsyncContext. All Bottom Halves belonging to the
 | 
			
		||||
 * old context are executed before changing the context.
 | 
			
		||||
 */
 | 
			
		||||
void async_context_pop(void)
 | 
			
		||||
{
 | 
			
		||||
    struct AsyncContext *old = async_context;
 | 
			
		||||
    QEMUBH **bh;
 | 
			
		||||
 | 
			
		||||
    /* Flush the bottom halves, we don't want to lose them */
 | 
			
		||||
    while (qemu_bh_poll());
 | 
			
		||||
 | 
			
		||||
    /* Switch back to the parent context */
 | 
			
		||||
    async_context = async_context->parent;
 | 
			
		||||
    qemu_free(old);
 | 
			
		||||
 | 
			
		||||
    if (async_context == NULL) {
 | 
			
		||||
        abort();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Schedule BH to run any queued AIO completions as soon as possible */
 | 
			
		||||
    bh = qemu_malloc(sizeof(*bh));
 | 
			
		||||
    *bh = qemu_bh_new(bh_run_aio_completions, bh);
 | 
			
		||||
    qemu_bh_schedule(*bh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns the ID of the currently active AsyncContext
 | 
			
		||||
 */
 | 
			
		||||
int get_async_context_id(void)
 | 
			
		||||
{
 | 
			
		||||
    return async_context->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***********************************************************/
 | 
			
		||||
/* bottom halves (can be seen as timers which expire ASAP) */
 | 
			
		||||
@@ -35,34 +118,30 @@ static struct QEMUBH *first_bh;
 | 
			
		||||
struct QEMUBH {
 | 
			
		||||
    QEMUBHFunc *cb;
 | 
			
		||||
    void *opaque;
 | 
			
		||||
    int scheduled;
 | 
			
		||||
    int idle;
 | 
			
		||||
    int deleted;
 | 
			
		||||
    QEMUBH *next;
 | 
			
		||||
    bool scheduled;
 | 
			
		||||
    bool idle;
 | 
			
		||||
    bool deleted;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
    bh = g_malloc0(sizeof(QEMUBH));
 | 
			
		||||
    bh = qemu_mallocz(sizeof(QEMUBH));
 | 
			
		||||
    bh->cb = cb;
 | 
			
		||||
    bh->opaque = opaque;
 | 
			
		||||
    bh->next = first_bh;
 | 
			
		||||
    first_bh = bh;
 | 
			
		||||
    bh->next = async_context->first_bh;
 | 
			
		||||
    async_context->first_bh = bh;
 | 
			
		||||
    return bh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qemu_bh_poll(void)
 | 
			
		||||
{
 | 
			
		||||
    QEMUBH *bh, **bhp, *next;
 | 
			
		||||
    QEMUBH *bh, **bhp;
 | 
			
		||||
    int ret;
 | 
			
		||||
    static int nesting = 0;
 | 
			
		||||
 | 
			
		||||
    nesting++;
 | 
			
		||||
 | 
			
		||||
    ret = 0;
 | 
			
		||||
    for (bh = first_bh; bh; bh = next) {
 | 
			
		||||
        next = bh->next;
 | 
			
		||||
    for (bh = async_context->first_bh; bh; bh = bh->next) {
 | 
			
		||||
        if (!bh->deleted && bh->scheduled) {
 | 
			
		||||
            bh->scheduled = 0;
 | 
			
		||||
            if (!bh->idle)
 | 
			
		||||
@@ -72,21 +151,16 @@ int qemu_bh_poll(void)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    nesting--;
 | 
			
		||||
 | 
			
		||||
    /* remove deleted bhs */
 | 
			
		||||
    if (!nesting) {
 | 
			
		||||
        bhp = &first_bh;
 | 
			
		||||
    bhp = &async_context->first_bh;
 | 
			
		||||
    while (*bhp) {
 | 
			
		||||
        bh = *bhp;
 | 
			
		||||
        if (bh->deleted) {
 | 
			
		||||
            *bhp = bh->next;
 | 
			
		||||
                g_free(bh);
 | 
			
		||||
            } else {
 | 
			
		||||
            qemu_free(bh);
 | 
			
		||||
        } else
 | 
			
		||||
            bhp = &bh->next;
 | 
			
		||||
    }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
@@ -120,11 +194,11 @@ void qemu_bh_delete(QEMUBH *bh)
 | 
			
		||||
    bh->deleted = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_bh_update_timeout(uint32_t *timeout)
 | 
			
		||||
void qemu_bh_update_timeout(int *timeout)
 | 
			
		||||
{
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
 | 
			
		||||
    for (bh = first_bh; bh; bh = bh->next) {
 | 
			
		||||
    for (bh = async_context->first_bh; bh; bh = bh->next) {
 | 
			
		||||
        if (!bh->deleted && bh->scheduled) {
 | 
			
		||||
            if (bh->idle) {
 | 
			
		||||
                /* idle bottom halves will be polled at least
 | 
			
		||||
 
 | 
			
		||||
@@ -136,7 +136,7 @@ static void alsa_fini_poll (struct pollhlp *hlp)
 | 
			
		||||
        for (i = 0; i < hlp->count; ++i) {
 | 
			
		||||
            qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
 | 
			
		||||
        }
 | 
			
		||||
        g_free (pfds);
 | 
			
		||||
        qemu_free (pfds);
 | 
			
		||||
    }
 | 
			
		||||
    hlp->pfds = NULL;
 | 
			
		||||
    hlp->count = 0;
 | 
			
		||||
@@ -260,7 +260,7 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
 | 
			
		||||
    if (err < 0) {
 | 
			
		||||
        alsa_logerr (err, "Could not initialize poll mode\n"
 | 
			
		||||
                     "Could not obtain poll descriptors\n");
 | 
			
		||||
        g_free (pfds);
 | 
			
		||||
        qemu_free (pfds);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -288,7 +288,7 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
 | 
			
		||||
            while (i--) {
 | 
			
		||||
                qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
 | 
			
		||||
            }
 | 
			
		||||
            g_free (pfds);
 | 
			
		||||
            qemu_free (pfds);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -318,7 +318,7 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
 | 
			
		||||
    return audio_pcm_sw_write (sw, buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
 | 
			
		||||
static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
 | 
			
		||||
{
 | 
			
		||||
    switch (fmt) {
 | 
			
		||||
    case AUD_FMT_S8:
 | 
			
		||||
@@ -328,36 +328,16 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
 | 
			
		||||
        return SND_PCM_FORMAT_U8;
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_S16:
 | 
			
		||||
        if (endianness) {
 | 
			
		||||
            return SND_PCM_FORMAT_S16_BE;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
        return SND_PCM_FORMAT_S16_LE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_U16:
 | 
			
		||||
        if (endianness) {
 | 
			
		||||
            return SND_PCM_FORMAT_U16_BE;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
        return SND_PCM_FORMAT_U16_LE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_S32:
 | 
			
		||||
        if (endianness) {
 | 
			
		||||
            return SND_PCM_FORMAT_S32_BE;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
        return SND_PCM_FORMAT_S32_LE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_U32:
 | 
			
		||||
        if (endianness) {
 | 
			
		||||
            return SND_PCM_FORMAT_U32_BE;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
        return SND_PCM_FORMAT_U32_LE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 | 
			
		||||
@@ -431,11 +411,10 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void alsa_dump_info (struct alsa_params_req *req,
 | 
			
		||||
                            struct alsa_params_obt *obt,
 | 
			
		||||
                            snd_pcm_format_t obtfmt)
 | 
			
		||||
                            struct alsa_params_obt *obt)
 | 
			
		||||
{
 | 
			
		||||
    dolog ("parameter | requested value | obtained value\n");
 | 
			
		||||
    dolog ("format    |      %10d |     %10d\n", req->fmt, obtfmt);
 | 
			
		||||
    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
 | 
			
		||||
    dolog ("channels  |      %10d |     %10d\n",
 | 
			
		||||
           req->nchannels, obt->nchannels);
 | 
			
		||||
    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
 | 
			
		||||
@@ -687,15 +666,15 @@ static int alsa_open (int in, struct alsa_params_req *req,
 | 
			
		||||
    *handlep = handle;
 | 
			
		||||
 | 
			
		||||
    if (conf.verbose &&
 | 
			
		||||
        (obtfmt != req->fmt ||
 | 
			
		||||
        (obt->fmt != req->fmt ||
 | 
			
		||||
         obt->nchannels != req->nchannels ||
 | 
			
		||||
         obt->freq != req->freq)) {
 | 
			
		||||
        dolog ("Audio parameters for %s\n", typ);
 | 
			
		||||
        alsa_dump_info (req, obt, obtfmt);
 | 
			
		||||
        alsa_dump_info (req, obt);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
    alsa_dump_info (req, obt, obtfmt);
 | 
			
		||||
    alsa_dump_info (req, obt);
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
@@ -816,7 +795,7 @@ static void alsa_fini_out (HWVoiceOut *hw)
 | 
			
		||||
    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 | 
			
		||||
 | 
			
		||||
    if (alsa->pcm_buf) {
 | 
			
		||||
        g_free (alsa->pcm_buf);
 | 
			
		||||
        qemu_free (alsa->pcm_buf);
 | 
			
		||||
        alsa->pcm_buf = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -829,7 +808,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    snd_pcm_t *handle;
 | 
			
		||||
    struct audsettings obt_as;
 | 
			
		||||
 | 
			
		||||
    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
 | 
			
		||||
    req.fmt = aud_to_alsafmt (as->fmt);
 | 
			
		||||
    req.freq = as->freq;
 | 
			
		||||
    req.nchannels = as->nchannels;
 | 
			
		||||
    req.period_size = conf.period_size_out;
 | 
			
		||||
@@ -863,15 +842,11 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define VOICE_CTL_PAUSE 0
 | 
			
		||||
#define VOICE_CTL_PREPARE 1
 | 
			
		||||
#define VOICE_CTL_START 2
 | 
			
		||||
 | 
			
		||||
static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
 | 
			
		||||
static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
 | 
			
		||||
{
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
    if (ctl == VOICE_CTL_PAUSE) {
 | 
			
		||||
    if (pause) {
 | 
			
		||||
        err = snd_pcm_drop (handle);
 | 
			
		||||
        if (err < 0) {
 | 
			
		||||
            alsa_logerr (err, "Could not stop %s\n", typ);
 | 
			
		||||
@@ -884,13 +859,6 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
 | 
			
		||||
            alsa_logerr (err, "Could not prepare handle for %s\n", typ);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        if (ctl == VOICE_CTL_START) {
 | 
			
		||||
            err = snd_pcm_start(handle);
 | 
			
		||||
            if (err < 0) {
 | 
			
		||||
                alsa_logerr (err, "Could not start handle for %s\n", typ);
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
@@ -915,16 +883,12 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
 | 
			
		||||
                poll_mode = 0;
 | 
			
		||||
            }
 | 
			
		||||
            hw->poll_mode = poll_mode;
 | 
			
		||||
            return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE);
 | 
			
		||||
            return alsa_voice_ctl (alsa->handle, "playback", 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    case VOICE_DISABLE:
 | 
			
		||||
        ldebug ("disabling voice\n");
 | 
			
		||||
        if (hw->poll_mode) {
 | 
			
		||||
            hw->poll_mode = 0;
 | 
			
		||||
            alsa_fini_poll (&alsa->pollhlp);
 | 
			
		||||
        }
 | 
			
		||||
        return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
 | 
			
		||||
        return alsa_voice_ctl (alsa->handle, "playback", 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
@@ -938,7 +902,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
    snd_pcm_t *handle;
 | 
			
		||||
    struct audsettings obt_as;
 | 
			
		||||
 | 
			
		||||
    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
 | 
			
		||||
    req.fmt = aud_to_alsafmt (as->fmt);
 | 
			
		||||
    req.freq = as->freq;
 | 
			
		||||
    req.nchannels = as->nchannels;
 | 
			
		||||
    req.period_size = conf.period_size_in;
 | 
			
		||||
@@ -979,7 +943,7 @@ static void alsa_fini_in (HWVoiceIn *hw)
 | 
			
		||||
    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 | 
			
		||||
 | 
			
		||||
    if (alsa->pcm_buf) {
 | 
			
		||||
        g_free (alsa->pcm_buf);
 | 
			
		||||
        qemu_free (alsa->pcm_buf);
 | 
			
		||||
        alsa->pcm_buf = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1097,7 +1061,7 @@ static int alsa_run_in (HWVoiceIn *hw)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            hw->conv (dst, src, nread);
 | 
			
		||||
            hw->conv (dst, src, nread, &nominal_volume);
 | 
			
		||||
 | 
			
		||||
            src = advance (src, nread << hwshift);
 | 
			
		||||
            dst += nread;
 | 
			
		||||
@@ -1137,7 +1101,7 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 | 
			
		||||
            }
 | 
			
		||||
            hw->poll_mode = poll_mode;
 | 
			
		||||
 | 
			
		||||
            return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START);
 | 
			
		||||
            return alsa_voice_ctl (alsa->handle, "capture", 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    case VOICE_DISABLE:
 | 
			
		||||
@@ -1146,7 +1110,7 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 | 
			
		||||
            hw->poll_mode = 0;
 | 
			
		||||
            alsa_fini_poll (&alsa->pollhlp);
 | 
			
		||||
        }
 | 
			
		||||
        return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE);
 | 
			
		||||
        return alsa_voice_ctl (alsa->handle, "capture", 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										111
									
								
								audio/audio.c
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								audio/audio.c
									
									
									
									
									
								
							@@ -44,9 +44,6 @@
 | 
			
		||||
    that we generate the list.
 | 
			
		||||
*/
 | 
			
		||||
static struct audio_driver *drvtab[] = {
 | 
			
		||||
#ifdef CONFIG_SPICE
 | 
			
		||||
    &spice_audio_driver,
 | 
			
		||||
#endif
 | 
			
		||||
    CONFIG_AUDIO_DRIVERS
 | 
			
		||||
    &no_audio_driver,
 | 
			
		||||
    &wav_audio_driver
 | 
			
		||||
@@ -104,7 +101,7 @@ static struct {
 | 
			
		||||
 | 
			
		||||
static AudioState glob_audio_state;
 | 
			
		||||
 | 
			
		||||
const struct mixeng_volume nominal_volume = {
 | 
			
		||||
struct mixeng_volume nominal_volume = {
 | 
			
		||||
    .mute = 0,
 | 
			
		||||
#ifdef FLOAT_MIXENG
 | 
			
		||||
    .r = 1.0,
 | 
			
		||||
@@ -118,9 +115,6 @@ const struct mixeng_volume nominal_volume = {
 | 
			
		||||
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
 | 
			
		||||
#error No its not
 | 
			
		||||
#else
 | 
			
		||||
static void audio_print_options (const char *prefix,
 | 
			
		||||
                                 struct audio_option *opt);
 | 
			
		||||
 | 
			
		||||
int audio_bug (const char *funcname, int cond)
 | 
			
		||||
{
 | 
			
		||||
    if (cond) {
 | 
			
		||||
@@ -128,16 +122,10 @@ int audio_bug (const char *funcname, int cond)
 | 
			
		||||
 | 
			
		||||
        AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
 | 
			
		||||
        if (!shown) {
 | 
			
		||||
            struct audio_driver *d;
 | 
			
		||||
 | 
			
		||||
            shown = 1;
 | 
			
		||||
            AUD_log (NULL, "Save all your work and restart without audio\n");
 | 
			
		||||
            AUD_log (NULL, "Please send bug report to av1474@comtv.ru\n");
 | 
			
		||||
            AUD_log (NULL, "I am sorry\n");
 | 
			
		||||
            d = glob_audio_state.drv;
 | 
			
		||||
            if (d) {
 | 
			
		||||
                audio_print_options (d->name, d->options);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        AUD_log (NULL, "Context:\n");
 | 
			
		||||
 | 
			
		||||
@@ -196,7 +184,7 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return g_malloc0 (len);
 | 
			
		||||
    return qemu_mallocz (len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *audio_alloc_prefix (const char *s)
 | 
			
		||||
@@ -210,7 +198,7 @@ static char *audio_alloc_prefix (const char *s)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    len = strlen (s);
 | 
			
		||||
    r = g_malloc (len + sizeof (qemu_prefix));
 | 
			
		||||
    r = qemu_malloc (len + sizeof (qemu_prefix));
 | 
			
		||||
 | 
			
		||||
    u = r + sizeof (qemu_prefix) - 1;
 | 
			
		||||
 | 
			
		||||
@@ -333,10 +321,10 @@ void AUD_vlog (const char *cap, const char *fmt, va_list ap)
 | 
			
		||||
{
 | 
			
		||||
    if (conf.log_to_monitor) {
 | 
			
		||||
        if (cap) {
 | 
			
		||||
            monitor_printf(default_mon, "%s: ", cap);
 | 
			
		||||
            monitor_printf(cur_mon, "%s: ", cap);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        monitor_vprintf(default_mon, fmt, ap);
 | 
			
		||||
        monitor_vprintf(cur_mon, fmt, ap);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        if (cap) {
 | 
			
		||||
@@ -425,7 +413,7 @@ static void audio_print_options (const char *prefix,
 | 
			
		||||
        printf ("    %s\n", opt->descr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free (uprefix);
 | 
			
		||||
    qemu_free (uprefix);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void audio_process_options (const char *prefix,
 | 
			
		||||
@@ -462,7 +450,7 @@ static void audio_process_options (const char *prefix,
 | 
			
		||||
         * (includes trailing zero) + zero + underscore (on behalf of
 | 
			
		||||
         * sizeof) */
 | 
			
		||||
        optlen = len + preflen + sizeof (qemu_prefix) + 1;
 | 
			
		||||
        optname = g_malloc (optlen);
 | 
			
		||||
        optname = qemu_malloc (optlen);
 | 
			
		||||
 | 
			
		||||
        pstrcpy (optname, optlen, qemu_prefix);
 | 
			
		||||
 | 
			
		||||
@@ -507,7 +495,7 @@ static void audio_process_options (const char *prefix,
 | 
			
		||||
            opt->overriddenp = &opt->overridden;
 | 
			
		||||
        }
 | 
			
		||||
        *opt->overriddenp = !def;
 | 
			
		||||
        g_free (optname);
 | 
			
		||||
        qemu_free (optname);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -585,20 +573,17 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
 | 
			
		||||
    switch (as->fmt) {
 | 
			
		||||
    case AUD_FMT_S8:
 | 
			
		||||
        sign = 1;
 | 
			
		||||
        /* fall through */
 | 
			
		||||
    case AUD_FMT_U8:
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_S16:
 | 
			
		||||
        sign = 1;
 | 
			
		||||
        /* fall through */
 | 
			
		||||
    case AUD_FMT_U16:
 | 
			
		||||
        bits = 16;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_S32:
 | 
			
		||||
        sign = 1;
 | 
			
		||||
        /* fall through */
 | 
			
		||||
    case AUD_FMT_U32:
 | 
			
		||||
        bits = 32;
 | 
			
		||||
        break;
 | 
			
		||||
@@ -705,11 +690,13 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
 | 
			
		||||
/*
 | 
			
		||||
 * Capture
 | 
			
		||||
 */
 | 
			
		||||
static void noop_conv (struct st_sample *dst, const void *src, int samples)
 | 
			
		||||
static void noop_conv (struct st_sample *dst, const void *src,
 | 
			
		||||
                       int samples, struct mixeng_volume *vol)
 | 
			
		||||
{
 | 
			
		||||
    (void) src;
 | 
			
		||||
    (void) dst;
 | 
			
		||||
    (void) samples;
 | 
			
		||||
    (void) vol;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static CaptureVoiceOut *audio_pcm_capture_find_specific (
 | 
			
		||||
@@ -781,7 +768,7 @@ static void audio_detach_capture (HWVoiceOut *hw)
 | 
			
		||||
 | 
			
		||||
        QLIST_REMOVE (sw, entries);
 | 
			
		||||
        QLIST_REMOVE (sc, entries);
 | 
			
		||||
        g_free (sc);
 | 
			
		||||
        qemu_free (sc);
 | 
			
		||||
        if (was_active) {
 | 
			
		||||
            /* We have removed soft voice from the capture:
 | 
			
		||||
               this might have changed the overall status of the capture
 | 
			
		||||
@@ -821,7 +808,7 @@ static int audio_attach_capture (HWVoiceOut *hw)
 | 
			
		||||
        sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
 | 
			
		||||
        if (!sw->rate) {
 | 
			
		||||
            dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
 | 
			
		||||
            g_free (sw);
 | 
			
		||||
            qemu_free (sw);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
 | 
			
		||||
@@ -957,10 +944,6 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
 | 
			
		||||
        total += isamp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) {
 | 
			
		||||
        mixeng_volume (sw->buf, ret, &sw->vol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sw->clip (buf, sw->buf, ret);
 | 
			
		||||
    sw->total_hw_samples_acquired += total;
 | 
			
		||||
    return ret << sw->info.shift;
 | 
			
		||||
@@ -1042,11 +1025,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
 | 
			
		||||
    swlim = ((int64_t) dead << 32) / sw->ratio;
 | 
			
		||||
    swlim = audio_MIN (swlim, samples);
 | 
			
		||||
    if (swlim) {
 | 
			
		||||
        sw->conv (sw->buf, buf, swlim);
 | 
			
		||||
 | 
			
		||||
        if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) {
 | 
			
		||||
            mixeng_volume (sw->buf, swlim, &sw->vol);
 | 
			
		||||
        }
 | 
			
		||||
        sw->conv (sw->buf, buf, swlim, &sw->vol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (swlim) {
 | 
			
		||||
@@ -1105,6 +1084,15 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
 | 
			
		||||
/*
 | 
			
		||||
 * Timer
 | 
			
		||||
 */
 | 
			
		||||
static void audio_timer (void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    AudioState *s = opaque;
 | 
			
		||||
 | 
			
		||||
    audio_run ("timer");
 | 
			
		||||
    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int audio_is_timer_needed (void)
 | 
			
		||||
{
 | 
			
		||||
    HWVoiceIn *hwi = NULL;
 | 
			
		||||
@@ -1119,22 +1107,18 @@ static int audio_is_timer_needed (void)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void audio_reset_timer (AudioState *s)
 | 
			
		||||
static void audio_reset_timer (void)
 | 
			
		||||
{
 | 
			
		||||
    AudioState *s = &glob_audio_state;
 | 
			
		||||
 | 
			
		||||
    if (audio_is_timer_needed ()) {
 | 
			
		||||
        qemu_mod_timer (s->ts, qemu_get_clock_ns (vm_clock) + 1);
 | 
			
		||||
        qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        qemu_del_timer (s->ts);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void audio_timer (void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    audio_run ("timer");
 | 
			
		||||
    audio_reset_timer (opaque);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Public API
 | 
			
		||||
 */
 | 
			
		||||
@@ -1199,7 +1183,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
 | 
			
		||||
                hw->enabled = 1;
 | 
			
		||||
                if (s->vm_running) {
 | 
			
		||||
                    hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
 | 
			
		||||
                    audio_reset_timer (s);
 | 
			
		||||
                    audio_reset_timer ();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -1244,7 +1228,6 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
 | 
			
		||||
                hw->enabled = 1;
 | 
			
		||||
                if (s->vm_running) {
 | 
			
		||||
                    hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
 | 
			
		||||
                    audio_reset_timer (s);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            sw->total_hw_samples_acquired = hw->total_samples_captured;
 | 
			
		||||
@@ -1673,7 +1656,7 @@ static void audio_pp_nb_voices (const char *typ, int nb)
 | 
			
		||||
        printf ("Theoretically supports many %s voices\n", typ);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        printf ("Theoretically supports up to %d %s voices\n", nb, typ);
 | 
			
		||||
        printf ("Theoretically supports upto %d %s voices\n", nb, typ);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1751,7 +1734,7 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void audio_vm_change_state_handler (void *opaque, int running,
 | 
			
		||||
                                           RunState state)
 | 
			
		||||
                                           int reason)
 | 
			
		||||
{
 | 
			
		||||
    AudioState *s = opaque;
 | 
			
		||||
    HWVoiceOut *hwo = NULL;
 | 
			
		||||
@@ -1766,7 +1749,7 @@ static void audio_vm_change_state_handler (void *opaque, int running,
 | 
			
		||||
    while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
 | 
			
		||||
        hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
 | 
			
		||||
    }
 | 
			
		||||
    audio_reset_timer (s);
 | 
			
		||||
    audio_reset_timer ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void audio_atexit (void)
 | 
			
		||||
@@ -1828,7 +1811,7 @@ static void audio_init (void)
 | 
			
		||||
    QLIST_INIT (&s->cap_head);
 | 
			
		||||
    atexit (audio_atexit);
 | 
			
		||||
 | 
			
		||||
    s->ts = qemu_new_timer_ns (vm_clock, audio_timer, s);
 | 
			
		||||
    s->ts = qemu_new_timer (vm_clock, audio_timer, s);
 | 
			
		||||
    if (!s->ts) {
 | 
			
		||||
        hw_error("Could not create audio timer\n");
 | 
			
		||||
    }
 | 
			
		||||
@@ -1909,13 +1892,13 @@ static void audio_init (void)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QLIST_INIT (&s->card_head);
 | 
			
		||||
    vmstate_register (NULL, 0, &vmstate_audio, s);
 | 
			
		||||
    vmstate_register (0, &vmstate_audio, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AUD_register_card (const char *name, QEMUSoundCard *card)
 | 
			
		||||
{
 | 
			
		||||
    audio_init ();
 | 
			
		||||
    card->name = g_strdup (name);
 | 
			
		||||
    card->name = qemu_strdup (name);
 | 
			
		||||
    memset (&card->entries, 0, sizeof (card->entries));
 | 
			
		||||
    QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
 | 
			
		||||
}
 | 
			
		||||
@@ -1923,7 +1906,7 @@ void AUD_register_card (const char *name, QEMUSoundCard *card)
 | 
			
		||||
void AUD_remove_card (QEMUSoundCard *card)
 | 
			
		||||
{
 | 
			
		||||
    QLIST_REMOVE (card, entries);
 | 
			
		||||
    g_free (card->name);
 | 
			
		||||
    qemu_free (card->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -2008,11 +1991,11 @@ CaptureVoiceOut *AUD_add_capture (
 | 
			
		||||
        return cap;
 | 
			
		||||
 | 
			
		||||
    err3:
 | 
			
		||||
        g_free (cap->hw.mix_buf);
 | 
			
		||||
        qemu_free (cap->hw.mix_buf);
 | 
			
		||||
    err2:
 | 
			
		||||
        g_free (cap);
 | 
			
		||||
        qemu_free (cap);
 | 
			
		||||
    err1:
 | 
			
		||||
        g_free (cb);
 | 
			
		||||
        qemu_free (cb);
 | 
			
		||||
    err0:
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
@@ -2026,7 +2009,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
 | 
			
		||||
        if (cb->opaque == cb_opaque) {
 | 
			
		||||
            cb->ops.destroy (cb_opaque);
 | 
			
		||||
            QLIST_REMOVE (cb, entries);
 | 
			
		||||
            g_free (cb);
 | 
			
		||||
            qemu_free (cb);
 | 
			
		||||
 | 
			
		||||
            if (!cap->cb_head.lh_first) {
 | 
			
		||||
                SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
 | 
			
		||||
@@ -2044,11 +2027,11 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
 | 
			
		||||
                    }
 | 
			
		||||
                    QLIST_REMOVE (sw, entries);
 | 
			
		||||
                    QLIST_REMOVE (sc, entries);
 | 
			
		||||
                    g_free (sc);
 | 
			
		||||
                    qemu_free (sc);
 | 
			
		||||
                    sw = sw1;
 | 
			
		||||
                }
 | 
			
		||||
                QLIST_REMOVE (cap, entries);
 | 
			
		||||
                g_free (cap);
 | 
			
		||||
                qemu_free (cap);
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -2058,29 +2041,17 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
 | 
			
		||||
void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
 | 
			
		||||
{
 | 
			
		||||
    if (sw) {
 | 
			
		||||
        HWVoiceOut *hw = sw->hw;
 | 
			
		||||
 | 
			
		||||
        sw->vol.mute = mute;
 | 
			
		||||
        sw->vol.l = nominal_volume.l * lvol / 255;
 | 
			
		||||
        sw->vol.r = nominal_volume.r * rvol / 255;
 | 
			
		||||
 | 
			
		||||
        if (hw->pcm_ops->ctl_out) {
 | 
			
		||||
            hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
 | 
			
		||||
{
 | 
			
		||||
    if (sw) {
 | 
			
		||||
        HWVoiceIn *hw = sw->hw;
 | 
			
		||||
 | 
			
		||||
        sw->vol.mute = mute;
 | 
			
		||||
        sw->vol.l = nominal_volume.l * lvol / 255;
 | 
			
		||||
        sw->vol.r = nominal_volume.r * rvol / 255;
 | 
			
		||||
 | 
			
		||||
        if (hw->pcm_ops->ctl_in) {
 | 
			
		||||
            hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -86,8 +86,12 @@ typedef struct QEMUAudioTimeStamp {
 | 
			
		||||
    uint64_t old_ts;
 | 
			
		||||
} QEMUAudioTimeStamp;
 | 
			
		||||
 | 
			
		||||
void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
 | 
			
		||||
void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 | 
			
		||||
void AUD_vlog (const char *cap, const char *fmt, va_list ap);
 | 
			
		||||
void AUD_log (const char *cap, const char *fmt, ...)
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
    __attribute__ ((__format__ (__printf__, 2, 3)))
 | 
			
		||||
#endif
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
void AUD_help (void);
 | 
			
		||||
void AUD_register_card (const char *name, QEMUSoundCard *card);
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,6 @@ typedef struct HWVoiceOut {
 | 
			
		||||
    int samples;
 | 
			
		||||
    QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
 | 
			
		||||
    QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
 | 
			
		||||
    int ctl_caps;
 | 
			
		||||
    struct audio_pcm_ops *pcm_ops;
 | 
			
		||||
    QLIST_ENTRY (HWVoiceOut) entries;
 | 
			
		||||
} HWVoiceOut;
 | 
			
		||||
@@ -102,7 +101,6 @@ typedef struct HWVoiceIn {
 | 
			
		||||
 | 
			
		||||
    int samples;
 | 
			
		||||
    QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
 | 
			
		||||
    int ctl_caps;
 | 
			
		||||
    struct audio_pcm_ops *pcm_ops;
 | 
			
		||||
    QLIST_ENTRY (HWVoiceIn) entries;
 | 
			
		||||
} HWVoiceIn;
 | 
			
		||||
@@ -152,7 +150,6 @@ struct audio_driver {
 | 
			
		||||
    int max_voices_in;
 | 
			
		||||
    int voice_size_out;
 | 
			
		||||
    int voice_size_in;
 | 
			
		||||
    int ctl_caps;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct audio_pcm_ops {
 | 
			
		||||
@@ -212,9 +209,8 @@ extern struct audio_driver coreaudio_audio_driver;
 | 
			
		||||
extern struct audio_driver dsound_audio_driver;
 | 
			
		||||
extern struct audio_driver esd_audio_driver;
 | 
			
		||||
extern struct audio_driver pa_audio_driver;
 | 
			
		||||
extern struct audio_driver spice_audio_driver;
 | 
			
		||||
extern struct audio_driver winwave_audio_driver;
 | 
			
		||||
extern const struct mixeng_volume nominal_volume;
 | 
			
		||||
extern struct mixeng_volume nominal_volume;
 | 
			
		||||
 | 
			
		||||
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 | 
			
		||||
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
 | 
			
		||||
@@ -234,15 +230,20 @@ void audio_run (const char *msg);
 | 
			
		||||
 | 
			
		||||
#define VOICE_ENABLE 1
 | 
			
		||||
#define VOICE_DISABLE 2
 | 
			
		||||
#define VOICE_VOLUME 3
 | 
			
		||||
 | 
			
		||||
#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
 | 
			
		||||
 | 
			
		||||
static inline int audio_ring_dist (int dst, int src, int len)
 | 
			
		||||
{
 | 
			
		||||
    return (dst >= src) ? (dst - src) : (len - src + dst);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined __GNUC__
 | 
			
		||||
#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
 | 
			
		||||
#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (__printf__, n, m)))
 | 
			
		||||
#else
 | 
			
		||||
#define GCC_ATTR /**/
 | 
			
		||||
#define GCC_FMT_ATTR(n, m)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void GCC_ATTR dolog (const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
    va_list ap;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,7 @@
 | 
			
		||||
#include "audio_int.h"
 | 
			
		||||
#include "audio_pt_int.h"
 | 
			
		||||
 | 
			
		||||
static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err,
 | 
			
		||||
                                       const char *fmt, ...)
 | 
			
		||||
static void logerr (struct audio_pt *pt, int err, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
    va_list ap;
 | 
			
		||||
 | 
			
		||||
@@ -24,16 +23,9 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
 | 
			
		||||
{
 | 
			
		||||
    int err, err2;
 | 
			
		||||
    const char *efunc;
 | 
			
		||||
    sigset_t set, old_set;
 | 
			
		||||
 | 
			
		||||
    p->drv = drv;
 | 
			
		||||
 | 
			
		||||
    err = sigfillset (&set);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        logerr (p, errno, "%s(%s): sigfillset failed", cap, AUDIO_FUNC);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    err = pthread_mutex_init (&p->mutex, NULL);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        efunc = "pthread_mutex_init";
 | 
			
		||||
@@ -46,23 +38,7 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
 | 
			
		||||
        goto err1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        efunc = "pthread_sigmask";
 | 
			
		||||
        goto err2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    err = pthread_create (&p->thread, NULL, func, opaque);
 | 
			
		||||
 | 
			
		||||
    err2 = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
 | 
			
		||||
    if (err2) {
 | 
			
		||||
        logerr (p, err2, "%s(%s): pthread_sigmask (restore) failed",
 | 
			
		||||
                cap, AUDIO_FUNC);
 | 
			
		||||
        /* We have failed to restore original signal mask, all bets are off,
 | 
			
		||||
           so terminate the process */
 | 
			
		||||
        exit (EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (err) {
 | 
			
		||||
        efunc = "pthread_create";
 | 
			
		||||
        goto err2;
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
 | 
			
		||||
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
 | 
			
		||||
{
 | 
			
		||||
    if (HWBUF) {
 | 
			
		||||
        g_free (HWBUF);
 | 
			
		||||
        qemu_free (HWBUF);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HWBUF = NULL;
 | 
			
		||||
@@ -93,7 +93,7 @@ static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
 | 
			
		||||
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
 | 
			
		||||
{
 | 
			
		||||
    if (sw->buf) {
 | 
			
		||||
        g_free (sw->buf);
 | 
			
		||||
        qemu_free (sw->buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sw->rate) {
 | 
			
		||||
@@ -108,7 +108,11 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 | 
			
		||||
{
 | 
			
		||||
    int samples;
 | 
			
		||||
 | 
			
		||||
#ifdef DAC
 | 
			
		||||
    samples = sw->hw->samples;
 | 
			
		||||
#else
 | 
			
		||||
    samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
 | 
			
		||||
    if (!sw->buf) {
 | 
			
		||||
@@ -123,7 +127,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 | 
			
		||||
    sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
 | 
			
		||||
#endif
 | 
			
		||||
    if (!sw->rate) {
 | 
			
		||||
        g_free (sw->buf);
 | 
			
		||||
        qemu_free (sw->buf);
 | 
			
		||||
        sw->buf = NULL;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
@@ -160,10 +164,10 @@ static int glue (audio_pcm_sw_init_, TYPE) (
 | 
			
		||||
        [sw->info.swap_endianness]
 | 
			
		||||
        [audio_bits_to_index (sw->info.bits)];
 | 
			
		||||
 | 
			
		||||
    sw->name = g_strdup (name);
 | 
			
		||||
    sw->name = qemu_strdup (name);
 | 
			
		||||
    err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        g_free (sw->name);
 | 
			
		||||
        qemu_free (sw->name);
 | 
			
		||||
        sw->name = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return err;
 | 
			
		||||
@@ -173,7 +177,7 @@ static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
 | 
			
		||||
{
 | 
			
		||||
    glue (audio_pcm_sw_free_resources_, TYPE) (sw);
 | 
			
		||||
    if (sw->name) {
 | 
			
		||||
        g_free (sw->name);
 | 
			
		||||
        qemu_free (sw->name);
 | 
			
		||||
        sw->name = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -201,7 +205,7 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
 | 
			
		||||
        glue (s->nb_hw_voices_, TYPE) += 1;
 | 
			
		||||
        glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
 | 
			
		||||
        glue (hw->pcm_ops->fini_, TYPE) (hw);
 | 
			
		||||
        g_free (hw);
 | 
			
		||||
        qemu_free (hw);
 | 
			
		||||
        *hwp = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -263,8 +267,6 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hw->pcm_ops = drv->pcm_ops;
 | 
			
		||||
    hw->ctl_caps = drv->ctl_caps;
 | 
			
		||||
 | 
			
		||||
    QLIST_INIT (&hw->sw_head);
 | 
			
		||||
#ifdef DAC
 | 
			
		||||
    QLIST_INIT (&hw->cap_head);
 | 
			
		||||
@@ -302,7 +304,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
 | 
			
		||||
 err1:
 | 
			
		||||
    glue (hw->pcm_ops->fini_, TYPE) (hw);
 | 
			
		||||
 err0:
 | 
			
		||||
    g_free (hw);
 | 
			
		||||
    qemu_free (hw);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -370,7 +372,7 @@ err3:
 | 
			
		||||
    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
 | 
			
		||||
    glue (audio_pcm_hw_gc_, TYPE) (&hw);
 | 
			
		||||
err2:
 | 
			
		||||
    g_free (sw);
 | 
			
		||||
    qemu_free (sw);
 | 
			
		||||
err1:
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
@@ -380,7 +382,7 @@ static void glue (audio_close_, TYPE) (SW *sw)
 | 
			
		||||
    glue (audio_pcm_sw_fini_, TYPE) (sw);
 | 
			
		||||
    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
 | 
			
		||||
    glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
 | 
			
		||||
    g_free (sw);
 | 
			
		||||
    qemu_free (sw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
 | 
			
		||||
@@ -539,7 +541,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
 | 
			
		||||
 | 
			
		||||
    cur_ts = sw->hw->ts_helper;
 | 
			
		||||
    old_ts = ts->old_ts;
 | 
			
		||||
    /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
 | 
			
		||||
    /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
 | 
			
		||||
 | 
			
		||||
    if (cur_ts >= old_ts) {
 | 
			
		||||
        delta = cur_ts - old_ts;
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ typedef struct coreaudioVoiceOut {
 | 
			
		||||
 | 
			
		||||
static void coreaudio_logstatus (OSStatus status)
 | 
			
		||||
{
 | 
			
		||||
    const char *str = "BUG";
 | 
			
		||||
    char *str = "BUG";
 | 
			
		||||
 | 
			
		||||
    switch(status) {
 | 
			
		||||
    case kAudioHardwareNoError:
 | 
			
		||||
@@ -104,7 +104,7 @@ static void coreaudio_logstatus (OSStatus status)
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
 | 
			
		||||
        AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -360,8 +360,8 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
        &core->audioDevicePropertyBufferFrameSize);
 | 
			
		||||
    if (status != kAudioHardwareNoError) {
 | 
			
		||||
        coreaudio_logerr2 (status, typ,
 | 
			
		||||
                           "Could not set device buffer frame size %" PRIu32 "\n",
 | 
			
		||||
                           (uint32_t)core->audioDevicePropertyBufferFrameSize);
 | 
			
		||||
                           "Could not set device buffer frame size %ld\n",
 | 
			
		||||
                           core->audioDevicePropertyBufferFrameSize);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -831,11 +831,11 @@ static int dsound_run_in (HWVoiceIn *hw)
 | 
			
		||||
    decr = len1 + len2;
 | 
			
		||||
 | 
			
		||||
    if (p1 && len1) {
 | 
			
		||||
        hw->conv (hw->conv_buf + hw->wpos, p1, len1);
 | 
			
		||||
        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (p2 && len2) {
 | 
			
		||||
        hw->conv (hw->conv_buf, p2, len2);
 | 
			
		||||
        hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dsound_unlock_in (dscb, p1, p2, blen1, blen2);
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include <esd.h>
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "audio.h"
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
 | 
			
		||||
#define AUDIO_CAP "esd"
 | 
			
		||||
#include "audio_int.h"
 | 
			
		||||
@@ -189,6 +190,10 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
 | 
			
		||||
    struct audsettings obt_as = *as;
 | 
			
		||||
    int esdfmt = ESD_STREAM | ESD_PLAY;
 | 
			
		||||
    int err;
 | 
			
		||||
    sigset_t set, old_set;
 | 
			
		||||
 | 
			
		||||
    sigfillset (&set);
 | 
			
		||||
 | 
			
		||||
    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
 | 
			
		||||
    switch (as->fmt) {
 | 
			
		||||
@@ -201,7 +206,7 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    case AUD_FMT_S32:
 | 
			
		||||
    case AUD_FMT_U32:
 | 
			
		||||
        dolog ("Will use 16 instead of 32 bit samples\n");
 | 
			
		||||
        /* fall through */
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_S16:
 | 
			
		||||
    case AUD_FMT_U16:
 | 
			
		||||
    deffmt:
 | 
			
		||||
@@ -226,27 +231,45 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
 | 
			
		||||
    if (esd->fd < 0) {
 | 
			
		||||
        qesd_logerr (errno, "esd_play_stream failed\n");
 | 
			
		||||
    esd->fd = -1;
 | 
			
		||||
    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        qesd_logerr (err, "pthread_sigmask failed\n");
 | 
			
		||||
        goto fail1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
 | 
			
		||||
    esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
 | 
			
		||||
    if (esd->fd < 0) {
 | 
			
		||||
        qesd_logerr (errno, "esd_play_stream failed\n");
 | 
			
		||||
        goto fail2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
 | 
			
		||||
        goto fail3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
 fail2:
 | 
			
		||||
 fail3:
 | 
			
		||||
    if (close (esd->fd)) {
 | 
			
		||||
        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
 | 
			
		||||
                     AUDIO_FUNC, esd->fd);
 | 
			
		||||
    }
 | 
			
		||||
    esd->fd = -1;
 | 
			
		||||
 | 
			
		||||
 fail2:
 | 
			
		||||
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 fail1:
 | 
			
		||||
    g_free (esd->pcm_buf);
 | 
			
		||||
    qemu_free (esd->pcm_buf);
 | 
			
		||||
    esd->pcm_buf = NULL;
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -270,7 +293,7 @@ static void qesd_fini_out (HWVoiceOut *hw)
 | 
			
		||||
 | 
			
		||||
    audio_pt_fini (&esd->pt, AUDIO_FUNC);
 | 
			
		||||
 | 
			
		||||
    g_free (esd->pcm_buf);
 | 
			
		||||
    qemu_free (esd->pcm_buf);
 | 
			
		||||
    esd->pcm_buf = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -346,7 +369,8 @@ static void *qesd_thread_in (void *arg)
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift);
 | 
			
		||||
            hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
 | 
			
		||||
                      &nominal_volume);
 | 
			
		||||
            wpos = (wpos + chunk) % hw->samples;
 | 
			
		||||
            to_grab -= chunk;
 | 
			
		||||
        }
 | 
			
		||||
@@ -399,6 +423,10 @@ static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
 | 
			
		||||
    struct audsettings obt_as = *as;
 | 
			
		||||
    int esdfmt = ESD_STREAM | ESD_RECORD;
 | 
			
		||||
    int err;
 | 
			
		||||
    sigset_t set, old_set;
 | 
			
		||||
 | 
			
		||||
    sigfillset (&set);
 | 
			
		||||
 | 
			
		||||
    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
 | 
			
		||||
    switch (as->fmt) {
 | 
			
		||||
@@ -433,27 +461,46 @@ static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
 | 
			
		||||
    if (esd->fd < 0) {
 | 
			
		||||
        qesd_logerr (errno, "esd_record_stream failed\n");
 | 
			
		||||
    esd->fd = -1;
 | 
			
		||||
 | 
			
		||||
    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        qesd_logerr (err, "pthread_sigmask failed\n");
 | 
			
		||||
        goto fail1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
 | 
			
		||||
    esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
 | 
			
		||||
    if (esd->fd < 0) {
 | 
			
		||||
        qesd_logerr (errno, "esd_record_stream failed\n");
 | 
			
		||||
        goto fail2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
 | 
			
		||||
        goto fail3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
 fail2:
 | 
			
		||||
 fail3:
 | 
			
		||||
    if (close (esd->fd)) {
 | 
			
		||||
        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
 | 
			
		||||
                     AUDIO_FUNC, esd->fd);
 | 
			
		||||
    }
 | 
			
		||||
    esd->fd = -1;
 | 
			
		||||
 | 
			
		||||
 fail2:
 | 
			
		||||
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 fail1:
 | 
			
		||||
    g_free (esd->pcm_buf);
 | 
			
		||||
    qemu_free (esd->pcm_buf);
 | 
			
		||||
    esd->pcm_buf = NULL;
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -477,7 +524,7 @@ static void qesd_fini_in (HWVoiceIn *hw)
 | 
			
		||||
 | 
			
		||||
    audio_pt_fini (&esd->pt, AUDIO_FUNC);
 | 
			
		||||
 | 
			
		||||
    g_free (esd->pcm_buf);
 | 
			
		||||
    qemu_free (esd->pcm_buf);
 | 
			
		||||
    esd->pcm_buf = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -343,7 +343,7 @@ static void fmod_fini_out (HWVoiceOut *hw)
 | 
			
		||||
 | 
			
		||||
static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
{
 | 
			
		||||
    int mode, channel;
 | 
			
		||||
    int bits16, mode, channel;
 | 
			
		||||
    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
 | 
			
		||||
    struct audsettings obt_as = *as;
 | 
			
		||||
 | 
			
		||||
@@ -374,6 +374,7 @@ static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    /* FMOD always operates on little endian frames? */
 | 
			
		||||
    obt_as.endianness = 0;
 | 
			
		||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
			
		||||
    bits16 = (mode & FSOUND_16BITS) != 0;
 | 
			
		||||
    hw->samples = conf.nb_samples;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -404,7 +405,7 @@ static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
 | 
			
		||||
 | 
			
		||||
static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
{
 | 
			
		||||
    int mode;
 | 
			
		||||
    int bits16, mode;
 | 
			
		||||
    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
 | 
			
		||||
    struct audsettings obt_as = *as;
 | 
			
		||||
 | 
			
		||||
@@ -431,6 +432,7 @@ static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
    /* FMOD always operates on little endian frames? */
 | 
			
		||||
    obt_as.endianness = 0;
 | 
			
		||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
			
		||||
    bits16 = (mode & FSOUND_16BITS) != 0;
 | 
			
		||||
    hw->samples = conf.nb_samples;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -486,10 +488,10 @@ static int fmod_run_in (HWVoiceIn *hw)
 | 
			
		||||
    decr = len1 + len2;
 | 
			
		||||
 | 
			
		||||
    if (p1 && blen1) {
 | 
			
		||||
        hw->conv (hw->conv_buf + hw->wpos, p1, len1);
 | 
			
		||||
        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
 | 
			
		||||
    }
 | 
			
		||||
    if (p2 && len2) {
 | 
			
		||||
        hw->conv (hw->conv_buf, p2, len2);
 | 
			
		||||
        hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
 | 
			
		||||
 
 | 
			
		||||
@@ -123,7 +123,7 @@
 | 
			
		||||
#undef IN_T
 | 
			
		||||
#undef SHIFT
 | 
			
		||||
 | 
			
		||||
/* Unsigned 32 bit */
 | 
			
		||||
/* Unsigned 16 bit */
 | 
			
		||||
#define IN_T uint32_t
 | 
			
		||||
#define IN_MIN 0
 | 
			
		||||
#define IN_MAX UINT32_MAX
 | 
			
		||||
@@ -326,35 +326,10 @@ void *st_rate_start (int inrate, int outrate)
 | 
			
		||||
 | 
			
		||||
void st_rate_stop (void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    g_free (opaque);
 | 
			
		||||
    qemu_free (opaque);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mixeng_clear (struct st_sample *buf, int len)
 | 
			
		||||
{
 | 
			
		||||
    memset (buf, 0, len * sizeof (struct st_sample));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_MIXEMU
 | 
			
		||||
    if (vol->mute) {
 | 
			
		||||
        mixeng_clear (buf, len);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (len--) {
 | 
			
		||||
#ifdef FLOAT_MIXENG
 | 
			
		||||
        buf->l = buf->l * vol->l;
 | 
			
		||||
        buf->r = buf->r * vol->r;
 | 
			
		||||
#else
 | 
			
		||||
        buf->l = (buf->l * vol->l) >> 32;
 | 
			
		||||
        buf->r = (buf->r * vol->r) >> 32;
 | 
			
		||||
#endif
 | 
			
		||||
        buf += 1;
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    (void) buf;
 | 
			
		||||
    (void) len;
 | 
			
		||||
    (void) vol;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,8 @@ struct mixeng_volume { int mute; int64_t r; int64_t l; };
 | 
			
		||||
struct st_sample { int64_t l; int64_t r; };
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
 | 
			
		||||
typedef void (t_sample) (struct st_sample *dst, const void *src,
 | 
			
		||||
                         int samples, struct mixeng_volume *vol);
 | 
			
		||||
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
 | 
			
		||||
 | 
			
		||||
extern t_sample *mixeng_conv[2][2][2][3];
 | 
			
		||||
@@ -46,6 +47,5 @@ void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *o
 | 
			
		||||
                       int *isamp, int *osamp);
 | 
			
		||||
void st_rate_stop (void *opaque);
 | 
			
		||||
void mixeng_clear (struct st_sample *buf, int len);
 | 
			
		||||
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
 | 
			
		||||
 | 
			
		||||
#endif  /* mixeng.h */
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,16 @@
 | 
			
		||||
#define HALF (IN_MAX >> 1)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MIXEMU
 | 
			
		||||
#ifdef FLOAT_MIXENG
 | 
			
		||||
#define VOL(a, b) ((a) * (b))
 | 
			
		||||
#else
 | 
			
		||||
#define VOL(a, b) ((a) * (b)) >> 32
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
#define VOL(a, b) a
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
 | 
			
		||||
 | 
			
		||||
#ifdef FLOAT_MIXENG
 | 
			
		||||
@@ -46,7 +56,7 @@ static mixeng_real inline glue (conv_, ET) (IN_T v)
 | 
			
		||||
#endif
 | 
			
		||||
#else  /* !RECIPROCAL */
 | 
			
		||||
#ifdef SIGNED
 | 
			
		||||
    return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN);
 | 
			
		||||
    return nv / (mixeng_real) (IN_MAX - IN_MIN);
 | 
			
		||||
#else
 | 
			
		||||
    return (nv - HALF) / (mixeng_real) IN_MAX;
 | 
			
		||||
#endif
 | 
			
		||||
@@ -63,7 +73,7 @@ static IN_T inline glue (clip_, ET) (mixeng_real v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef SIGNED
 | 
			
		||||
    return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real) IN_MAX - IN_MIN)));
 | 
			
		||||
    return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN)));
 | 
			
		||||
#else
 | 
			
		||||
    return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
 | 
			
		||||
#endif
 | 
			
		||||
@@ -99,26 +109,40 @@ static inline IN_T glue (clip_, ET) (int64_t v)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void glue (glue (conv_, ET), _to_stereo)
 | 
			
		||||
    (struct st_sample *dst, const void *src, int samples)
 | 
			
		||||
    (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
 | 
			
		||||
{
 | 
			
		||||
    struct st_sample *out = dst;
 | 
			
		||||
    IN_T *in = (IN_T *) src;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MIXEMU
 | 
			
		||||
    if (vol->mute) {
 | 
			
		||||
        mixeng_clear (dst, samples);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    (void) vol;
 | 
			
		||||
#endif
 | 
			
		||||
    while (samples--) {
 | 
			
		||||
        out->l = glue (conv_, ET) (*in++);
 | 
			
		||||
        out->r = glue (conv_, ET) (*in++);
 | 
			
		||||
        out->l = VOL (glue (conv_, ET) (*in++), vol->l);
 | 
			
		||||
        out->r = VOL (glue (conv_, ET) (*in++), vol->r);
 | 
			
		||||
        out += 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void glue (glue (conv_, ET), _to_mono)
 | 
			
		||||
    (struct st_sample *dst, const void *src, int samples)
 | 
			
		||||
    (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
 | 
			
		||||
{
 | 
			
		||||
    struct st_sample *out = dst;
 | 
			
		||||
    IN_T *in = (IN_T *) src;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MIXEMU
 | 
			
		||||
    if (vol->mute) {
 | 
			
		||||
        mixeng_clear (dst, samples);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    (void) vol;
 | 
			
		||||
#endif
 | 
			
		||||
    while (samples--) {
 | 
			
		||||
        out->l = glue (conv_, ET) (in[0]);
 | 
			
		||||
        out->l = VOL (glue (conv_, ET) (in[0]), vol->l);
 | 
			
		||||
        out->r = out->l;
 | 
			
		||||
        out += 1;
 | 
			
		||||
        in += 1;
 | 
			
		||||
@@ -150,3 +174,4 @@ static void glue (glue (clip_, ET), _from_mono)
 | 
			
		||||
 | 
			
		||||
#undef ET
 | 
			
		||||
#undef HALF
 | 
			
		||||
#undef VOL
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ static int no_run_out (HWVoiceOut *hw, int live)
 | 
			
		||||
    int64_t ticks;
 | 
			
		||||
    int64_t bytes;
 | 
			
		||||
 | 
			
		||||
    now = qemu_get_clock_ns (vm_clock);
 | 
			
		||||
    now = qemu_get_clock (vm_clock);
 | 
			
		||||
    ticks = now - no->old_ticks;
 | 
			
		||||
    bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
 | 
			
		||||
    bytes = audio_MIN (bytes, INT_MAX);
 | 
			
		||||
@@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw)
 | 
			
		||||
    int samples = 0;
 | 
			
		||||
 | 
			
		||||
    if (dead) {
 | 
			
		||||
        int64_t now = qemu_get_clock_ns (vm_clock);
 | 
			
		||||
        int64_t now = qemu_get_clock (vm_clock);
 | 
			
		||||
        int64_t ticks = now - no->old_ticks;
 | 
			
		||||
        int64_t bytes =
 | 
			
		||||
            muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
 | 
			
		||||
@@ -117,14 +117,11 @@ static int no_run_in (HWVoiceIn *hw)
 | 
			
		||||
 | 
			
		||||
static int no_read (SWVoiceIn *sw, void *buf, int size)
 | 
			
		||||
{
 | 
			
		||||
    /* use custom code here instead of audio_pcm_sw_read() to avoid
 | 
			
		||||
     * useless resampling/mixing */
 | 
			
		||||
    int samples = size >> sw->info.shift;
 | 
			
		||||
    int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
 | 
			
		||||
    int to_clear = audio_MIN (samples, total);
 | 
			
		||||
    sw->total_hw_samples_acquired += total;
 | 
			
		||||
    audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
 | 
			
		||||
    return to_clear << sw->info.shift;
 | 
			
		||||
    return to_clear;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
 | 
			
		||||
 
 | 
			
		||||
@@ -161,7 +161,7 @@ static int oss_write (SWVoiceOut *sw, void *buf, int len)
 | 
			
		||||
    return audio_pcm_sw_write (sw, buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int aud_to_ossfmt (audfmt_e fmt, int endianness)
 | 
			
		||||
static int aud_to_ossfmt (audfmt_e fmt)
 | 
			
		||||
{
 | 
			
		||||
    switch (fmt) {
 | 
			
		||||
    case AUD_FMT_S8:
 | 
			
		||||
@@ -171,20 +171,10 @@ static int aud_to_ossfmt (audfmt_e fmt, int endianness)
 | 
			
		||||
        return AFMT_U8;
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_S16:
 | 
			
		||||
        if (endianness) {
 | 
			
		||||
            return AFMT_S16_BE;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
        return AFMT_S16_LE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_U16:
 | 
			
		||||
        if (endianness) {
 | 
			
		||||
            return AFMT_U16_BE;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
        return AFMT_U16_LE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 | 
			
		||||
@@ -508,7 +498,7 @@ static void oss_fini_out (HWVoiceOut *hw)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            g_free (oss->pcm_buf);
 | 
			
		||||
            qemu_free (oss->pcm_buf);
 | 
			
		||||
        }
 | 
			
		||||
        oss->pcm_buf = NULL;
 | 
			
		||||
    }
 | 
			
		||||
@@ -526,7 +516,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
 | 
			
		||||
    oss->fd = -1;
 | 
			
		||||
 | 
			
		||||
    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 | 
			
		||||
    req.fmt = aud_to_ossfmt (as->fmt);
 | 
			
		||||
    req.freq = as->freq;
 | 
			
		||||
    req.nchannels = as->nchannels;
 | 
			
		||||
    req.fragsize = conf.fragsize;
 | 
			
		||||
@@ -692,7 +682,7 @@ static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
 | 
			
		||||
    oss->fd = -1;
 | 
			
		||||
 | 
			
		||||
    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 | 
			
		||||
    req.fmt = aud_to_ossfmt (as->fmt);
 | 
			
		||||
    req.freq = as->freq;
 | 
			
		||||
    req.nchannels = as->nchannels;
 | 
			
		||||
    req.fragsize = conf.fragsize;
 | 
			
		||||
@@ -741,7 +731,7 @@ static void oss_fini_in (HWVoiceIn *hw)
 | 
			
		||||
    oss_anal_close (&oss->fd);
 | 
			
		||||
 | 
			
		||||
    if (oss->pcm_buf) {
 | 
			
		||||
        g_free (oss->pcm_buf);
 | 
			
		||||
        qemu_free (oss->pcm_buf);
 | 
			
		||||
        oss->pcm_buf = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -788,7 +778,8 @@ static int oss_run_in (HWVoiceIn *hw)
 | 
			
		||||
                           hw->info.align + 1);
 | 
			
		||||
                }
 | 
			
		||||
                read_samples += nread >> hwshift;
 | 
			
		||||
                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
 | 
			
		||||
                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
 | 
			
		||||
                          &nominal_volume);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (bufs[i].len - nread) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										519
									
								
								audio/paaudio.c
									
									
									
									
									
								
							
							
						
						
									
										519
									
								
								audio/paaudio.c
									
									
									
									
									
								
							@@ -2,7 +2,8 @@
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "audio.h"
 | 
			
		||||
 | 
			
		||||
#include <pulse/pulseaudio.h>
 | 
			
		||||
#include <pulse/simple.h>
 | 
			
		||||
#include <pulse/error.h>
 | 
			
		||||
 | 
			
		||||
#define AUDIO_CAP "pulseaudio"
 | 
			
		||||
#include "audio_int.h"
 | 
			
		||||
@@ -14,7 +15,7 @@ typedef struct {
 | 
			
		||||
    int live;
 | 
			
		||||
    int decr;
 | 
			
		||||
    int rpos;
 | 
			
		||||
    pa_stream *stream;
 | 
			
		||||
    pa_simple *s;
 | 
			
		||||
    void *pcm_buf;
 | 
			
		||||
    struct audio_pt pt;
 | 
			
		||||
} PAVoiceOut;
 | 
			
		||||
@@ -25,24 +26,20 @@ typedef struct {
 | 
			
		||||
    int dead;
 | 
			
		||||
    int incr;
 | 
			
		||||
    int wpos;
 | 
			
		||||
    pa_stream *stream;
 | 
			
		||||
    pa_simple *s;
 | 
			
		||||
    void *pcm_buf;
 | 
			
		||||
    struct audio_pt pt;
 | 
			
		||||
    const void *read_data;
 | 
			
		||||
    size_t read_index, read_length;
 | 
			
		||||
} PAVoiceIn;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
static struct {
 | 
			
		||||
    int samples;
 | 
			
		||||
    int divisor;
 | 
			
		||||
    char *server;
 | 
			
		||||
    char *sink;
 | 
			
		||||
    char *source;
 | 
			
		||||
    pa_threaded_mainloop *mainloop;
 | 
			
		||||
    pa_context *context;
 | 
			
		||||
} paaudio;
 | 
			
		||||
 | 
			
		||||
static paaudio glob_paaudio = {
 | 
			
		||||
    .samples = 4096,
 | 
			
		||||
} conf = {
 | 
			
		||||
    .samples = 1024,
 | 
			
		||||
    .divisor = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
 | 
			
		||||
@@ -56,130 +53,13 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
 | 
			
		||||
    AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define CHECK_SUCCESS_GOTO(c, rerror, expression, label)        \
 | 
			
		||||
    do {                                                        \
 | 
			
		||||
        if (!(expression)) {                                    \
 | 
			
		||||
            if (rerror) {                                       \
 | 
			
		||||
                *(rerror) = pa_context_errno ((c)->context);    \
 | 
			
		||||
            }                                                   \
 | 
			
		||||
            goto label;                                         \
 | 
			
		||||
        }                                                       \
 | 
			
		||||
    } while (0);
 | 
			
		||||
 | 
			
		||||
#define CHECK_DEAD_GOTO(c, stream, rerror, label)                       \
 | 
			
		||||
    do {                                                                \
 | 
			
		||||
        if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
 | 
			
		||||
            !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
 | 
			
		||||
            if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
 | 
			
		||||
                ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
 | 
			
		||||
                if (rerror) {                                           \
 | 
			
		||||
                    *(rerror) = pa_context_errno ((c)->context);        \
 | 
			
		||||
                }                                                       \
 | 
			
		||||
            } else {                                                    \
 | 
			
		||||
                if (rerror) {                                           \
 | 
			
		||||
                    *(rerror) = PA_ERR_BADSTATE;                        \
 | 
			
		||||
                }                                                       \
 | 
			
		||||
            }                                                           \
 | 
			
		||||
            goto label;                                                 \
 | 
			
		||||
        }                                                               \
 | 
			
		||||
    } while (0);
 | 
			
		||||
 | 
			
		||||
static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
 | 
			
		||||
{
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_lock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
    CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
 | 
			
		||||
 | 
			
		||||
    while (length > 0) {
 | 
			
		||||
        size_t l;
 | 
			
		||||
 | 
			
		||||
        while (!p->read_data) {
 | 
			
		||||
            int r;
 | 
			
		||||
 | 
			
		||||
            r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
 | 
			
		||||
            CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
 | 
			
		||||
 | 
			
		||||
            if (!p->read_data) {
 | 
			
		||||
                pa_threaded_mainloop_wait (g->mainloop);
 | 
			
		||||
                CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
 | 
			
		||||
            } else {
 | 
			
		||||
                p->read_index = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        l = p->read_length < length ? p->read_length : length;
 | 
			
		||||
        memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
 | 
			
		||||
 | 
			
		||||
        data = (uint8_t *) data + l;
 | 
			
		||||
        length -= l;
 | 
			
		||||
 | 
			
		||||
        p->read_index += l;
 | 
			
		||||
        p->read_length -= l;
 | 
			
		||||
 | 
			
		||||
        if (!p->read_length) {
 | 
			
		||||
            int r;
 | 
			
		||||
 | 
			
		||||
            r = pa_stream_drop (p->stream);
 | 
			
		||||
            p->read_data = NULL;
 | 
			
		||||
            p->read_length = 0;
 | 
			
		||||
            p->read_index = 0;
 | 
			
		||||
 | 
			
		||||
            CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
unlock_and_fail:
 | 
			
		||||
    pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
 | 
			
		||||
{
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_lock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
    CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
 | 
			
		||||
 | 
			
		||||
    while (length > 0) {
 | 
			
		||||
        size_t l;
 | 
			
		||||
        int r;
 | 
			
		||||
 | 
			
		||||
        while (!(l = pa_stream_writable_size (p->stream))) {
 | 
			
		||||
            pa_threaded_mainloop_wait (g->mainloop);
 | 
			
		||||
            CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
 | 
			
		||||
 | 
			
		||||
        if (l > length) {
 | 
			
		||||
            l = length;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
 | 
			
		||||
        CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
 | 
			
		||||
 | 
			
		||||
        data = (const uint8_t *) data + l;
 | 
			
		||||
        length -= l;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
unlock_and_fail:
 | 
			
		||||
    pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *qpa_thread_out (void *arg)
 | 
			
		||||
{
 | 
			
		||||
    PAVoiceOut *pa = arg;
 | 
			
		||||
    HWVoiceOut *hw = &pa->hw;
 | 
			
		||||
    int threshold;
 | 
			
		||||
 | 
			
		||||
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
 | 
			
		||||
 | 
			
		||||
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
@@ -193,7 +73,7 @@ static void *qpa_thread_out (void *arg)
 | 
			
		||||
                goto exit;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (pa->live > 0) {
 | 
			
		||||
            if (pa->live > threshold) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -202,8 +82,8 @@ static void *qpa_thread_out (void *arg)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2);
 | 
			
		||||
        rpos = pa->rpos;
 | 
			
		||||
        decr = to_mix = pa->live;
 | 
			
		||||
        rpos = hw->rpos;
 | 
			
		||||
 | 
			
		||||
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
 | 
			
		||||
            return NULL;
 | 
			
		||||
@@ -216,7 +96,7 @@ static void *qpa_thread_out (void *arg)
 | 
			
		||||
 | 
			
		||||
            hw->clip (pa->pcm_buf, src, chunk);
 | 
			
		||||
 | 
			
		||||
            if (qpa_simple_write (pa, pa->pcm_buf,
 | 
			
		||||
            if (pa_simple_write (pa->s, pa->pcm_buf,
 | 
			
		||||
                                 chunk << hw->info.shift, &error) < 0) {
 | 
			
		||||
                qpa_logerr (error, "pa_simple_write failed\n");
 | 
			
		||||
                return NULL;
 | 
			
		||||
@@ -272,6 +152,9 @@ static void *qpa_thread_in (void *arg)
 | 
			
		||||
{
 | 
			
		||||
    PAVoiceIn *pa = arg;
 | 
			
		||||
    HWVoiceIn *hw = &pa->hw;
 | 
			
		||||
    int threshold;
 | 
			
		||||
 | 
			
		||||
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
 | 
			
		||||
 | 
			
		||||
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
@@ -285,7 +168,7 @@ static void *qpa_thread_in (void *arg)
 | 
			
		||||
                goto exit;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (pa->dead > 0) {
 | 
			
		||||
            if (pa->dead > threshold) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -294,8 +177,8 @@ static void *qpa_thread_in (void *arg)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2);
 | 
			
		||||
        wpos = pa->wpos;
 | 
			
		||||
        incr = to_grab = pa->dead;
 | 
			
		||||
        wpos = hw->wpos;
 | 
			
		||||
 | 
			
		||||
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
 | 
			
		||||
            return NULL;
 | 
			
		||||
@@ -306,13 +189,13 @@ static void *qpa_thread_in (void *arg)
 | 
			
		||||
            int chunk = audio_MIN (to_grab, hw->samples - wpos);
 | 
			
		||||
            void *buf = advance (pa->pcm_buf, wpos);
 | 
			
		||||
 | 
			
		||||
            if (qpa_simple_read (pa, buf,
 | 
			
		||||
            if (pa_simple_read (pa->s, buf,
 | 
			
		||||
                                chunk << hw->info.shift, &error) < 0) {
 | 
			
		||||
                qpa_logerr (error, "pa_simple_read failed\n");
 | 
			
		||||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            hw->conv (hw->conv_buf + wpos, buf, chunk);
 | 
			
		||||
            hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
 | 
			
		||||
            wpos = (wpos + chunk) % hw->samples;
 | 
			
		||||
            to_grab -= chunk;
 | 
			
		||||
        }
 | 
			
		||||
@@ -408,113 +291,10 @@ static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void context_state_cb (pa_context *c, void *userdata)
 | 
			
		||||
{
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
    switch (pa_context_get_state(c)) {
 | 
			
		||||
    case PA_CONTEXT_READY:
 | 
			
		||||
    case PA_CONTEXT_TERMINATED:
 | 
			
		||||
    case PA_CONTEXT_FAILED:
 | 
			
		||||
        pa_threaded_mainloop_signal (g->mainloop, 0);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case PA_CONTEXT_UNCONNECTED:
 | 
			
		||||
    case PA_CONTEXT_CONNECTING:
 | 
			
		||||
    case PA_CONTEXT_AUTHORIZING:
 | 
			
		||||
    case PA_CONTEXT_SETTING_NAME:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void stream_state_cb (pa_stream *s, void * userdata)
 | 
			
		||||
{
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
    switch (pa_stream_get_state (s)) {
 | 
			
		||||
 | 
			
		||||
    case PA_STREAM_READY:
 | 
			
		||||
    case PA_STREAM_FAILED:
 | 
			
		||||
    case PA_STREAM_TERMINATED:
 | 
			
		||||
        pa_threaded_mainloop_signal (g->mainloop, 0);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case PA_STREAM_UNCONNECTED:
 | 
			
		||||
    case PA_STREAM_CREATING:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
 | 
			
		||||
{
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_signal (g->mainloop, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static pa_stream *qpa_simple_new (
 | 
			
		||||
        const char *server,
 | 
			
		||||
        const char *name,
 | 
			
		||||
        pa_stream_direction_t dir,
 | 
			
		||||
        const char *dev,
 | 
			
		||||
        const char *stream_name,
 | 
			
		||||
        const pa_sample_spec *ss,
 | 
			
		||||
        const pa_channel_map *map,
 | 
			
		||||
        const pa_buffer_attr *attr,
 | 
			
		||||
        int *rerror)
 | 
			
		||||
{
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
    int r;
 | 
			
		||||
    pa_stream *stream;
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_lock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
    stream = pa_stream_new (g->context, name, ss, map);
 | 
			
		||||
    if (!stream) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_stream_set_state_callback (stream, stream_state_cb, g);
 | 
			
		||||
    pa_stream_set_read_callback (stream, stream_request_cb, g);
 | 
			
		||||
    pa_stream_set_write_callback (stream, stream_request_cb, g);
 | 
			
		||||
 | 
			
		||||
    if (dir == PA_STREAM_PLAYBACK) {
 | 
			
		||||
        r = pa_stream_connect_playback (stream, dev, attr,
 | 
			
		||||
                                        PA_STREAM_INTERPOLATE_TIMING
 | 
			
		||||
                                        |PA_STREAM_ADJUST_LATENCY
 | 
			
		||||
                                        |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
 | 
			
		||||
    } else {
 | 
			
		||||
        r = pa_stream_connect_record (stream, dev, attr,
 | 
			
		||||
                                      PA_STREAM_INTERPOLATE_TIMING
 | 
			
		||||
                                      |PA_STREAM_ADJUST_LATENCY
 | 
			
		||||
                                      |PA_STREAM_AUTO_TIMING_UPDATE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
      goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
    return stream;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
    if (stream) {
 | 
			
		||||
        pa_stream_unref (stream);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *rerror = pa_context_errno (g->context);
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
{
 | 
			
		||||
    int error;
 | 
			
		||||
    static pa_sample_spec ss;
 | 
			
		||||
    static pa_buffer_attr ba;
 | 
			
		||||
    struct audsettings obt_as = *as;
 | 
			
		||||
    PAVoiceOut *pa = (PAVoiceOut *) hw;
 | 
			
		||||
 | 
			
		||||
@@ -522,37 +302,27 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    ss.channels = as->nchannels;
 | 
			
		||||
    ss.rate = as->freq;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * qemu audio tick runs at 250 Hz (by default), so processing
 | 
			
		||||
     * data chunks worth 4 ms of sound should be a good fit.
 | 
			
		||||
     */
 | 
			
		||||
    ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
 | 
			
		||||
    ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
 | 
			
		||||
    ba.maxlength = -1;
 | 
			
		||||
    ba.prebuf = -1;
 | 
			
		||||
 | 
			
		||||
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 | 
			
		||||
 | 
			
		||||
    pa->stream = qpa_simple_new (
 | 
			
		||||
        glob_paaudio.server,
 | 
			
		||||
    pa->s = pa_simple_new (
 | 
			
		||||
        conf.server,
 | 
			
		||||
        "qemu",
 | 
			
		||||
        PA_STREAM_PLAYBACK,
 | 
			
		||||
        glob_paaudio.sink,
 | 
			
		||||
        conf.sink,
 | 
			
		||||
        "pcm.playback",
 | 
			
		||||
        &ss,
 | 
			
		||||
        NULL,                   /* channel map */
 | 
			
		||||
        &ba,                    /* buffering attributes */
 | 
			
		||||
        NULL,                   /* buffering attributes */
 | 
			
		||||
        &error
 | 
			
		||||
        );
 | 
			
		||||
    if (!pa->stream) {
 | 
			
		||||
    if (!pa->s) {
 | 
			
		||||
        qpa_logerr (error, "pa_simple_new for playback failed\n");
 | 
			
		||||
        goto fail1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
			
		||||
    hw->samples = glob_paaudio.samples;
 | 
			
		||||
    hw->samples = conf.samples;
 | 
			
		||||
    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 | 
			
		||||
    pa->rpos = hw->rpos;
 | 
			
		||||
    if (!pa->pcm_buf) {
 | 
			
		||||
        dolog ("Could not allocate buffer (%d bytes)\n",
 | 
			
		||||
               hw->samples << hw->info.shift);
 | 
			
		||||
@@ -566,13 +336,11 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
 fail3:
 | 
			
		||||
    g_free (pa->pcm_buf);
 | 
			
		||||
    qemu_free (pa->pcm_buf);
 | 
			
		||||
    pa->pcm_buf = NULL;
 | 
			
		||||
 fail2:
 | 
			
		||||
    if (pa->stream) {
 | 
			
		||||
        pa_stream_unref (pa->stream);
 | 
			
		||||
        pa->stream = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    pa_simple_free (pa->s);
 | 
			
		||||
    pa->s = NULL;
 | 
			
		||||
 fail1:
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -590,26 +358,25 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
 | 
			
		||||
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 | 
			
		||||
 | 
			
		||||
    pa->stream = qpa_simple_new (
 | 
			
		||||
        glob_paaudio.server,
 | 
			
		||||
    pa->s = pa_simple_new (
 | 
			
		||||
        conf.server,
 | 
			
		||||
        "qemu",
 | 
			
		||||
        PA_STREAM_RECORD,
 | 
			
		||||
        glob_paaudio.source,
 | 
			
		||||
        conf.source,
 | 
			
		||||
        "pcm.capture",
 | 
			
		||||
        &ss,
 | 
			
		||||
        NULL,                   /* channel map */
 | 
			
		||||
        NULL,                   /* buffering attributes */
 | 
			
		||||
        &error
 | 
			
		||||
        );
 | 
			
		||||
    if (!pa->stream) {
 | 
			
		||||
    if (!pa->s) {
 | 
			
		||||
        qpa_logerr (error, "pa_simple_new for capture failed\n");
 | 
			
		||||
        goto fail1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
			
		||||
    hw->samples = glob_paaudio.samples;
 | 
			
		||||
    hw->samples = conf.samples;
 | 
			
		||||
    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 | 
			
		||||
    pa->wpos = hw->wpos;
 | 
			
		||||
    if (!pa->pcm_buf) {
 | 
			
		||||
        dolog ("Could not allocate buffer (%d bytes)\n",
 | 
			
		||||
               hw->samples << hw->info.shift);
 | 
			
		||||
@@ -623,13 +390,11 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
 fail3:
 | 
			
		||||
    g_free (pa->pcm_buf);
 | 
			
		||||
    qemu_free (pa->pcm_buf);
 | 
			
		||||
    pa->pcm_buf = NULL;
 | 
			
		||||
 fail2:
 | 
			
		||||
    if (pa->stream) {
 | 
			
		||||
        pa_stream_unref (pa->stream);
 | 
			
		||||
        pa->stream = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    pa_simple_free (pa->s);
 | 
			
		||||
    pa->s = NULL;
 | 
			
		||||
 fail1:
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -644,13 +409,13 @@ static void qpa_fini_out (HWVoiceOut *hw)
 | 
			
		||||
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 | 
			
		||||
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 | 
			
		||||
 | 
			
		||||
    if (pa->stream) {
 | 
			
		||||
        pa_stream_unref (pa->stream);
 | 
			
		||||
        pa->stream = NULL;
 | 
			
		||||
    if (pa->s) {
 | 
			
		||||
        pa_simple_free (pa->s);
 | 
			
		||||
        pa->s = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
 | 
			
		||||
    g_free (pa->pcm_buf);
 | 
			
		||||
    qemu_free (pa->pcm_buf);
 | 
			
		||||
    pa->pcm_buf = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -664,221 +429,70 @@ static void qpa_fini_in (HWVoiceIn *hw)
 | 
			
		||||
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 | 
			
		||||
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 | 
			
		||||
 | 
			
		||||
    if (pa->stream) {
 | 
			
		||||
        pa_stream_unref (pa->stream);
 | 
			
		||||
        pa->stream = NULL;
 | 
			
		||||
    if (pa->s) {
 | 
			
		||||
        pa_simple_free (pa->s);
 | 
			
		||||
        pa->s = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
 | 
			
		||||
    g_free (pa->pcm_buf);
 | 
			
		||||
    qemu_free (pa->pcm_buf);
 | 
			
		||||
    pa->pcm_buf = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
 | 
			
		||||
{
 | 
			
		||||
    PAVoiceOut *pa = (PAVoiceOut *) hw;
 | 
			
		||||
    pa_operation *op;
 | 
			
		||||
    pa_cvolume v;
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
    pa_cvolume_init (&v);
 | 
			
		||||
 | 
			
		||||
    switch (cmd) {
 | 
			
		||||
    case VOICE_VOLUME:
 | 
			
		||||
        {
 | 
			
		||||
            SWVoiceOut *sw;
 | 
			
		||||
            va_list ap;
 | 
			
		||||
 | 
			
		||||
            va_start (ap, cmd);
 | 
			
		||||
            sw = va_arg (ap, SWVoiceOut *);
 | 
			
		||||
            va_end (ap);
 | 
			
		||||
 | 
			
		||||
            v.channels = 2;
 | 
			
		||||
            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
 | 
			
		||||
            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
 | 
			
		||||
 | 
			
		||||
            pa_threaded_mainloop_lock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
            op = pa_context_set_sink_input_volume (g->context,
 | 
			
		||||
                pa_stream_get_index (pa->stream),
 | 
			
		||||
                &v, NULL, NULL);
 | 
			
		||||
            if (!op)
 | 
			
		||||
                qpa_logerr (pa_context_errno (g->context),
 | 
			
		||||
                            "set_sink_input_volume() failed\n");
 | 
			
		||||
            else
 | 
			
		||||
                pa_operation_unref (op);
 | 
			
		||||
 | 
			
		||||
            op = pa_context_set_sink_input_mute (g->context,
 | 
			
		||||
                pa_stream_get_index (pa->stream),
 | 
			
		||||
               sw->vol.mute, NULL, NULL);
 | 
			
		||||
            if (!op) {
 | 
			
		||||
                qpa_logerr (pa_context_errno (g->context),
 | 
			
		||||
                            "set_sink_input_mute() failed\n");
 | 
			
		||||
            } else {
 | 
			
		||||
                pa_operation_unref (op);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    (void) hw;
 | 
			
		||||
    (void) cmd;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 | 
			
		||||
{
 | 
			
		||||
    PAVoiceIn *pa = (PAVoiceIn *) hw;
 | 
			
		||||
    pa_operation *op;
 | 
			
		||||
    pa_cvolume v;
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
    pa_cvolume_init (&v);
 | 
			
		||||
 | 
			
		||||
    switch (cmd) {
 | 
			
		||||
    case VOICE_VOLUME:
 | 
			
		||||
        {
 | 
			
		||||
            SWVoiceIn *sw;
 | 
			
		||||
            va_list ap;
 | 
			
		||||
 | 
			
		||||
            va_start (ap, cmd);
 | 
			
		||||
            sw = va_arg (ap, SWVoiceIn *);
 | 
			
		||||
            va_end (ap);
 | 
			
		||||
 | 
			
		||||
            v.channels = 2;
 | 
			
		||||
            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
 | 
			
		||||
            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
 | 
			
		||||
 | 
			
		||||
            pa_threaded_mainloop_lock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
            /* FIXME: use the upcoming "set_source_output_{volume,mute}" */
 | 
			
		||||
            op = pa_context_set_source_volume_by_index (g->context,
 | 
			
		||||
                pa_stream_get_device_index (pa->stream),
 | 
			
		||||
                &v, NULL, NULL);
 | 
			
		||||
            if (!op) {
 | 
			
		||||
                qpa_logerr (pa_context_errno (g->context),
 | 
			
		||||
                            "set_source_volume() failed\n");
 | 
			
		||||
            } else {
 | 
			
		||||
                pa_operation_unref(op);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            op = pa_context_set_source_mute_by_index (g->context,
 | 
			
		||||
                pa_stream_get_index (pa->stream),
 | 
			
		||||
                sw->vol.mute, NULL, NULL);
 | 
			
		||||
            if (!op) {
 | 
			
		||||
                qpa_logerr (pa_context_errno (g->context),
 | 
			
		||||
                            "set_source_mute() failed\n");
 | 
			
		||||
            } else {
 | 
			
		||||
                pa_operation_unref (op);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    (void) hw;
 | 
			
		||||
    (void) cmd;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* common */
 | 
			
		||||
static void *qpa_audio_init (void)
 | 
			
		||||
{
 | 
			
		||||
    paaudio *g = &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
    g->mainloop = pa_threaded_mainloop_new ();
 | 
			
		||||
    if (!g->mainloop) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server);
 | 
			
		||||
    if (!g->context) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_context_set_state_callback (g->context, context_state_cb, g);
 | 
			
		||||
 | 
			
		||||
    if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) {
 | 
			
		||||
        qpa_logerr (pa_context_errno (g->context),
 | 
			
		||||
                    "pa_context_connect() failed\n");
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_lock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
    if (pa_threaded_mainloop_start (g->mainloop) < 0) {
 | 
			
		||||
        goto unlock_and_fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        pa_context_state_t state;
 | 
			
		||||
 | 
			
		||||
        state = pa_context_get_state (g->context);
 | 
			
		||||
 | 
			
		||||
        if (state == PA_CONTEXT_READY) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!PA_CONTEXT_IS_GOOD (state)) {
 | 
			
		||||
            qpa_logerr (pa_context_errno (g->context),
 | 
			
		||||
                        "Wrong context state\n");
 | 
			
		||||
            goto unlock_and_fail;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Wait until the context is ready */
 | 
			
		||||
        pa_threaded_mainloop_wait (g->mainloop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
 | 
			
		||||
    return &glob_paaudio;
 | 
			
		||||
 | 
			
		||||
unlock_and_fail:
 | 
			
		||||
    pa_threaded_mainloop_unlock (g->mainloop);
 | 
			
		||||
fail:
 | 
			
		||||
    AUD_log (AUDIO_CAP, "Failed to initialize PA context");
 | 
			
		||||
    return NULL;
 | 
			
		||||
    return &conf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qpa_audio_fini (void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    paaudio *g = opaque;
 | 
			
		||||
 | 
			
		||||
    if (g->mainloop) {
 | 
			
		||||
        pa_threaded_mainloop_stop (g->mainloop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (g->context) {
 | 
			
		||||
        pa_context_disconnect (g->context);
 | 
			
		||||
        pa_context_unref (g->context);
 | 
			
		||||
        g->context = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (g->mainloop) {
 | 
			
		||||
        pa_threaded_mainloop_free (g->mainloop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g->mainloop = NULL;
 | 
			
		||||
    (void) opaque;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct audio_option qpa_options[] = {
 | 
			
		||||
    {
 | 
			
		||||
        .name  = "SAMPLES",
 | 
			
		||||
        .tag   = AUD_OPT_INT,
 | 
			
		||||
        .valp  = &glob_paaudio.samples,
 | 
			
		||||
        .valp  = &conf.samples,
 | 
			
		||||
        .descr = "buffer size in samples"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name  = "DIVISOR",
 | 
			
		||||
        .tag   = AUD_OPT_INT,
 | 
			
		||||
        .valp  = &conf.divisor,
 | 
			
		||||
        .descr = "threshold divisor"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name  = "SERVER",
 | 
			
		||||
        .tag   = AUD_OPT_STR,
 | 
			
		||||
        .valp  = &glob_paaudio.server,
 | 
			
		||||
        .valp  = &conf.server,
 | 
			
		||||
        .descr = "server address"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name  = "SINK",
 | 
			
		||||
        .tag   = AUD_OPT_STR,
 | 
			
		||||
        .valp  = &glob_paaudio.sink,
 | 
			
		||||
        .valp  = &conf.sink,
 | 
			
		||||
        .descr = "sink device name"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name  = "SOURCE",
 | 
			
		||||
        .tag   = AUD_OPT_STR,
 | 
			
		||||
        .valp  = &glob_paaudio.source,
 | 
			
		||||
        .valp  = &conf.source,
 | 
			
		||||
        .descr = "source device name"
 | 
			
		||||
    },
 | 
			
		||||
    { /* End of list */ }
 | 
			
		||||
@@ -909,6 +523,5 @@ struct audio_driver pa_audio_driver = {
 | 
			
		||||
    .max_voices_out = INT_MAX,
 | 
			
		||||
    .max_voices_in  = INT_MAX,
 | 
			
		||||
    .voice_size_out = sizeof (PAVoiceOut),
 | 
			
		||||
    .voice_size_in  = sizeof (PAVoiceIn),
 | 
			
		||||
    .ctl_caps       = VOICE_VOLUME_CAP
 | 
			
		||||
    .voice_size_in  = sizeof (PAVoiceIn)
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										114
									
								
								audio/sdlaudio.c
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								audio/sdlaudio.c
									
									
									
									
									
								
							@@ -32,6 +32,7 @@
 | 
			
		||||
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define AUDIO_CAP "sdl"
 | 
			
		||||
@@ -40,8 +41,8 @@
 | 
			
		||||
typedef struct SDLVoiceOut {
 | 
			
		||||
    HWVoiceOut hw;
 | 
			
		||||
    int live;
 | 
			
		||||
    int rpos;
 | 
			
		||||
    int decr;
 | 
			
		||||
    int pending;
 | 
			
		||||
} SDLVoiceOut;
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
@@ -114,19 +115,23 @@ static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
 | 
			
		||||
    return sdl_post (s, forfn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int aud_to_sdlfmt (audfmt_e fmt)
 | 
			
		||||
static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
 | 
			
		||||
{
 | 
			
		||||
    switch (fmt) {
 | 
			
		||||
    case AUD_FMT_S8:
 | 
			
		||||
        *shift = 0;
 | 
			
		||||
        return AUDIO_S8;
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_U8:
 | 
			
		||||
        *shift = 0;
 | 
			
		||||
        return AUDIO_U8;
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_S16:
 | 
			
		||||
        *shift = 1;
 | 
			
		||||
        return AUDIO_S16LSB;
 | 
			
		||||
 | 
			
		||||
    case AUD_FMT_U16:
 | 
			
		||||
        *shift = 1;
 | 
			
		||||
        return AUDIO_U16LSB;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
@@ -138,36 +143,36 @@ static int aud_to_sdlfmt (audfmt_e fmt)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness)
 | 
			
		||||
static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
 | 
			
		||||
{
 | 
			
		||||
    switch (sdlfmt) {
 | 
			
		||||
    case AUDIO_S8:
 | 
			
		||||
        *endianness = 0;
 | 
			
		||||
        *endianess = 0;
 | 
			
		||||
        *fmt = AUD_FMT_S8;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case AUDIO_U8:
 | 
			
		||||
        *endianness = 0;
 | 
			
		||||
        *endianess = 0;
 | 
			
		||||
        *fmt = AUD_FMT_U8;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case AUDIO_S16LSB:
 | 
			
		||||
        *endianness = 0;
 | 
			
		||||
        *endianess = 0;
 | 
			
		||||
        *fmt = AUD_FMT_S16;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case AUDIO_U16LSB:
 | 
			
		||||
        *endianness = 0;
 | 
			
		||||
        *endianess = 0;
 | 
			
		||||
        *fmt = AUD_FMT_U16;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case AUDIO_S16MSB:
 | 
			
		||||
        *endianness = 1;
 | 
			
		||||
        *endianess = 1;
 | 
			
		||||
        *fmt = AUD_FMT_S16;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case AUDIO_U16MSB:
 | 
			
		||||
        *endianness = 1;
 | 
			
		||||
        *endianess = 1;
 | 
			
		||||
        *fmt = AUD_FMT_U16;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
@@ -183,20 +188,11 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
 | 
			
		||||
{
 | 
			
		||||
    int status;
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
    int err;
 | 
			
		||||
    sigset_t new, old;
 | 
			
		||||
 | 
			
		||||
    /* Make sure potential threads created by SDL don't hog signals.  */
 | 
			
		||||
    err = sigfillset (&new);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno));
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    err = pthread_sigmask (SIG_BLOCK, &new, &old);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err));
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    sigfillset (&new);
 | 
			
		||||
    pthread_sigmask (SIG_BLOCK, &new, &old);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    status = SDL_OpenAudio (req, obt);
 | 
			
		||||
@@ -205,14 +201,7 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
    err = pthread_sigmask (SIG_SETMASK, &old, NULL);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        dolog ("sdl_open: pthread_sigmask (restore) failed: %s\n",
 | 
			
		||||
               strerror (errno));
 | 
			
		||||
        /* We have failed to restore original signal mask, all bets are off,
 | 
			
		||||
           so exit the process */
 | 
			
		||||
        exit (EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
    pthread_sigmask (SIG_SETMASK, &old, NULL);
 | 
			
		||||
#endif
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
@@ -236,6 +225,10 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
 | 
			
		||||
    HWVoiceOut *hw = &sdl->hw;
 | 
			
		||||
    int samples = len >> hw->info.shift;
 | 
			
		||||
 | 
			
		||||
    if (sdl_lock (s, "sdl_callback")) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->exit) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -243,7 +236,11 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
 | 
			
		||||
    while (samples) {
 | 
			
		||||
        int to_mix, decr;
 | 
			
		||||
 | 
			
		||||
        /* dolog ("in callback samples=%d\n", samples); */
 | 
			
		||||
        while (!sdl->pending) {
 | 
			
		||||
            if (sdl_unlock (s, "sdl_callback")) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            sdl_wait (s, "sdl_callback");
 | 
			
		||||
            if (s->exit) {
 | 
			
		||||
                return;
 | 
			
		||||
@@ -252,40 +249,21 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
 | 
			
		||||
            if (sdl_lock (s, "sdl_callback")) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
 | 
			
		||||
            dolog ("sdl->live=%d hw->samples=%d\n",
 | 
			
		||||
                   sdl->live, hw->samples);
 | 
			
		||||
            return;
 | 
			
		||||
            sdl->pending += sdl->live;
 | 
			
		||||
            sdl->live = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!sdl->live) {
 | 
			
		||||
            goto again;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* dolog ("in callback live=%d\n", live); */
 | 
			
		||||
        to_mix = audio_MIN (samples, sdl->live);
 | 
			
		||||
        decr = to_mix;
 | 
			
		||||
        while (to_mix) {
 | 
			
		||||
            int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
 | 
			
		||||
            struct st_sample *src = hw->mix_buf + hw->rpos;
 | 
			
		||||
 | 
			
		||||
            /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
 | 
			
		||||
            hw->clip (buf, src, chunk);
 | 
			
		||||
            sdl->rpos = (sdl->rpos + chunk) % hw->samples;
 | 
			
		||||
            to_mix -= chunk;
 | 
			
		||||
            buf += chunk << hw->info.shift;
 | 
			
		||||
        }
 | 
			
		||||
        to_mix = audio_MIN (samples, sdl->pending);
 | 
			
		||||
        decr = audio_pcm_hw_clip_out (hw, buf, to_mix, 0);
 | 
			
		||||
        buf += decr << hw->info.shift;
 | 
			
		||||
        samples -= decr;
 | 
			
		||||
        sdl->live -= decr;
 | 
			
		||||
        sdl->decr += decr;
 | 
			
		||||
        sdl->pending -= decr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    again:
 | 
			
		||||
    if (sdl_unlock (s, "sdl_callback")) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
    /* dolog ("done len=%d\n", len); */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
 | 
			
		||||
@@ -303,18 +281,9 @@ static int sdl_run_out (HWVoiceOut *hw, int live)
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sdl->decr > live) {
 | 
			
		||||
        ldebug ("sdl->decr %d live %d sdl->live %d\n",
 | 
			
		||||
                sdl->decr,
 | 
			
		||||
                live,
 | 
			
		||||
                sdl->live);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    decr = audio_MIN (sdl->decr, live);
 | 
			
		||||
    sdl->decr -= decr;
 | 
			
		||||
 | 
			
		||||
    sdl->live = live - decr;
 | 
			
		||||
    hw->rpos = sdl->rpos;
 | 
			
		||||
    sdl->live = live;
 | 
			
		||||
    decr = sdl->decr;
 | 
			
		||||
    sdl->decr = 0;
 | 
			
		||||
 | 
			
		||||
    if (sdl->live > 0) {
 | 
			
		||||
        sdl_unlock_and_post (s, "sdl_run_out");
 | 
			
		||||
@@ -337,13 +306,16 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
 | 
			
		||||
    SDLAudioState *s = &glob_sdl;
 | 
			
		||||
    SDL_AudioSpec req, obt;
 | 
			
		||||
    int endianness;
 | 
			
		||||
    int shift;
 | 
			
		||||
    int endianess;
 | 
			
		||||
    int err;
 | 
			
		||||
    audfmt_e effective_fmt;
 | 
			
		||||
    struct audsettings obt_as;
 | 
			
		||||
 | 
			
		||||
    shift <<= as->nchannels == 2;
 | 
			
		||||
 | 
			
		||||
    req.freq = as->freq;
 | 
			
		||||
    req.format = aud_to_sdlfmt (as->fmt);
 | 
			
		||||
    req.format = aud_to_sdlfmt (as->fmt, &shift);
 | 
			
		||||
    req.channels = as->nchannels;
 | 
			
		||||
    req.samples = conf.nb_samples;
 | 
			
		||||
    req.callback = sdl_callback;
 | 
			
		||||
@@ -353,7 +325,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
 | 
			
		||||
    err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        sdl_close (s);
 | 
			
		||||
        return -1;
 | 
			
		||||
@@ -362,7 +334,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    obt_as.freq = obt.freq;
 | 
			
		||||
    obt_as.nchannels = obt.channels;
 | 
			
		||||
    obt_as.fmt = effective_fmt;
 | 
			
		||||
    obt_as.endianness = endianness;
 | 
			
		||||
    obt_as.endianness = endianess;
 | 
			
		||||
 | 
			
		||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
			
		||||
    hw->samples = obt.samples;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,386 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2010 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * maintained by Gerd Hoffmann <kraxel@redhat.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 or
 | 
			
		||||
 * (at your option) version 3 of the License.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "hw/hw.h"
 | 
			
		||||
#include "qemu-timer.h"
 | 
			
		||||
#include "ui/qemu-spice.h"
 | 
			
		||||
 | 
			
		||||
#define AUDIO_CAP "spice"
 | 
			
		||||
#include "audio.h"
 | 
			
		||||
#include "audio_int.h"
 | 
			
		||||
 | 
			
		||||
#define LINE_IN_SAMPLES 1024
 | 
			
		||||
#define LINE_OUT_SAMPLES 1024
 | 
			
		||||
 | 
			
		||||
typedef struct SpiceRateCtl {
 | 
			
		||||
    int64_t               start_ticks;
 | 
			
		||||
    int64_t               bytes_sent;
 | 
			
		||||
} SpiceRateCtl;
 | 
			
		||||
 | 
			
		||||
typedef struct SpiceVoiceOut {
 | 
			
		||||
    HWVoiceOut            hw;
 | 
			
		||||
    SpicePlaybackInstance sin;
 | 
			
		||||
    SpiceRateCtl          rate;
 | 
			
		||||
    int                   active;
 | 
			
		||||
    uint32_t              *frame;
 | 
			
		||||
    uint32_t              *fpos;
 | 
			
		||||
    uint32_t              fsize;
 | 
			
		||||
} SpiceVoiceOut;
 | 
			
		||||
 | 
			
		||||
typedef struct SpiceVoiceIn {
 | 
			
		||||
    HWVoiceIn             hw;
 | 
			
		||||
    SpiceRecordInstance   sin;
 | 
			
		||||
    SpiceRateCtl          rate;
 | 
			
		||||
    int                   active;
 | 
			
		||||
    uint32_t              samples[LINE_IN_SAMPLES];
 | 
			
		||||
} SpiceVoiceIn;
 | 
			
		||||
 | 
			
		||||
static const SpicePlaybackInterface playback_sif = {
 | 
			
		||||
    .base.type          = SPICE_INTERFACE_PLAYBACK,
 | 
			
		||||
    .base.description   = "playback",
 | 
			
		||||
    .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
 | 
			
		||||
    .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const SpiceRecordInterface record_sif = {
 | 
			
		||||
    .base.type          = SPICE_INTERFACE_RECORD,
 | 
			
		||||
    .base.description   = "record",
 | 
			
		||||
    .base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
 | 
			
		||||
    .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void *spice_audio_init (void)
 | 
			
		||||
{
 | 
			
		||||
    if (!using_spice) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return &spice_audio_init;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void spice_audio_fini (void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    /* nothing */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rate_start (SpiceRateCtl *rate)
 | 
			
		||||
{
 | 
			
		||||
    memset (rate, 0, sizeof (*rate));
 | 
			
		||||
    rate->start_ticks = qemu_get_clock_ns (vm_clock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
 | 
			
		||||
{
 | 
			
		||||
    int64_t now;
 | 
			
		||||
    int64_t ticks;
 | 
			
		||||
    int64_t bytes;
 | 
			
		||||
    int64_t samples;
 | 
			
		||||
 | 
			
		||||
    now = qemu_get_clock_ns (vm_clock);
 | 
			
		||||
    ticks = now - rate->start_ticks;
 | 
			
		||||
    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);
 | 
			
		||||
        rate_start (rate);
 | 
			
		||||
        samples = 0;
 | 
			
		||||
    }
 | 
			
		||||
    rate->bytes_sent += samples << info->shift;
 | 
			
		||||
    return samples;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* playback */
 | 
			
		||||
 | 
			
		||||
static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
{
 | 
			
		||||
    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
 | 
			
		||||
    struct audsettings settings;
 | 
			
		||||
 | 
			
		||||
    settings.freq       = SPICE_INTERFACE_PLAYBACK_FREQ;
 | 
			
		||||
    settings.nchannels  = SPICE_INTERFACE_PLAYBACK_CHAN;
 | 
			
		||||
    settings.fmt        = AUD_FMT_S16;
 | 
			
		||||
    settings.endianness = AUDIO_HOST_ENDIANNESS;
 | 
			
		||||
 | 
			
		||||
    audio_pcm_init_info (&hw->info, &settings);
 | 
			
		||||
    hw->samples = LINE_OUT_SAMPLES;
 | 
			
		||||
    out->active = 0;
 | 
			
		||||
 | 
			
		||||
    out->sin.base.sif = &playback_sif.base;
 | 
			
		||||
    qemu_spice_add_interface (&out->sin.base);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void line_out_fini (HWVoiceOut *hw)
 | 
			
		||||
{
 | 
			
		||||
    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
 | 
			
		||||
 | 
			
		||||
    spice_server_remove_interface (&out->sin.base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int line_out_run (HWVoiceOut *hw, int live)
 | 
			
		||||
{
 | 
			
		||||
    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
 | 
			
		||||
    int rpos, decr;
 | 
			
		||||
    int samples;
 | 
			
		||||
 | 
			
		||||
    if (!live) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    decr = rate_get_samples (&hw->info, &out->rate);
 | 
			
		||||
    decr = audio_MIN (live, decr);
 | 
			
		||||
 | 
			
		||||
    samples = decr;
 | 
			
		||||
    rpos = hw->rpos;
 | 
			
		||||
    while (samples) {
 | 
			
		||||
        int left_till_end_samples = hw->samples - rpos;
 | 
			
		||||
        int len = audio_MIN (samples, left_till_end_samples);
 | 
			
		||||
 | 
			
		||||
        if (!out->frame) {
 | 
			
		||||
            spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
 | 
			
		||||
            out->fpos = out->frame;
 | 
			
		||||
        }
 | 
			
		||||
        if (out->frame) {
 | 
			
		||||
            len = audio_MIN (len, out->fsize);
 | 
			
		||||
            hw->clip (out->fpos, hw->mix_buf + rpos, len);
 | 
			
		||||
            out->fsize -= len;
 | 
			
		||||
            out->fpos  += len;
 | 
			
		||||
            if (out->fsize == 0) {
 | 
			
		||||
                spice_server_playback_put_samples (&out->sin, out->frame);
 | 
			
		||||
                out->frame = out->fpos = NULL;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        rpos = (rpos + len) % hw->samples;
 | 
			
		||||
        samples -= len;
 | 
			
		||||
    }
 | 
			
		||||
    hw->rpos = rpos;
 | 
			
		||||
    return decr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int line_out_write (SWVoiceOut *sw, void *buf, int len)
 | 
			
		||||
{
 | 
			
		||||
    return audio_pcm_sw_write (sw, buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
 | 
			
		||||
{
 | 
			
		||||
    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
 | 
			
		||||
 | 
			
		||||
    switch (cmd) {
 | 
			
		||||
    case VOICE_ENABLE:
 | 
			
		||||
        if (out->active) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        out->active = 1;
 | 
			
		||||
        rate_start (&out->rate);
 | 
			
		||||
        spice_server_playback_start (&out->sin);
 | 
			
		||||
        break;
 | 
			
		||||
    case VOICE_DISABLE:
 | 
			
		||||
        if (!out->active) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        out->active = 0;
 | 
			
		||||
        if (out->frame) {
 | 
			
		||||
            memset (out->fpos, 0, out->fsize << 2);
 | 
			
		||||
            spice_server_playback_put_samples (&out->sin, out->frame);
 | 
			
		||||
            out->frame = out->fpos = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        spice_server_playback_stop (&out->sin);
 | 
			
		||||
        break;
 | 
			
		||||
    case VOICE_VOLUME:
 | 
			
		||||
        {
 | 
			
		||||
#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
 | 
			
		||||
            SWVoiceOut *sw;
 | 
			
		||||
            va_list ap;
 | 
			
		||||
            uint16_t vol[2];
 | 
			
		||||
 | 
			
		||||
            va_start (ap, cmd);
 | 
			
		||||
            sw = va_arg (ap, SWVoiceOut *);
 | 
			
		||||
            va_end (ap);
 | 
			
		||||
 | 
			
		||||
            vol[0] = sw->vol.l / ((1ULL << 16) + 1);
 | 
			
		||||
            vol[1] = sw->vol.r / ((1ULL << 16) + 1);
 | 
			
		||||
            spice_server_playback_set_volume (&out->sin, 2, vol);
 | 
			
		||||
            spice_server_playback_set_mute (&out->sin, sw->vol.mute);
 | 
			
		||||
#endif
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* record */
 | 
			
		||||
 | 
			
		||||
static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
{
 | 
			
		||||
    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
 | 
			
		||||
    struct audsettings settings;
 | 
			
		||||
 | 
			
		||||
    settings.freq       = SPICE_INTERFACE_RECORD_FREQ;
 | 
			
		||||
    settings.nchannels  = SPICE_INTERFACE_RECORD_CHAN;
 | 
			
		||||
    settings.fmt        = AUD_FMT_S16;
 | 
			
		||||
    settings.endianness = AUDIO_HOST_ENDIANNESS;
 | 
			
		||||
 | 
			
		||||
    audio_pcm_init_info (&hw->info, &settings);
 | 
			
		||||
    hw->samples = LINE_IN_SAMPLES;
 | 
			
		||||
    in->active = 0;
 | 
			
		||||
 | 
			
		||||
    in->sin.base.sif = &record_sif.base;
 | 
			
		||||
    qemu_spice_add_interface (&in->sin.base);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void line_in_fini (HWVoiceIn *hw)
 | 
			
		||||
{
 | 
			
		||||
    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
 | 
			
		||||
 | 
			
		||||
    spice_server_remove_interface (&in->sin.base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int line_in_run (HWVoiceIn *hw)
 | 
			
		||||
{
 | 
			
		||||
    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
 | 
			
		||||
    int num_samples;
 | 
			
		||||
    int ready;
 | 
			
		||||
    int len[2];
 | 
			
		||||
    uint64_t delta_samp;
 | 
			
		||||
    const uint32_t *samples;
 | 
			
		||||
 | 
			
		||||
    if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    delta_samp = rate_get_samples (&hw->info, &in->rate);
 | 
			
		||||
    num_samples = audio_MIN (num_samples, delta_samp);
 | 
			
		||||
 | 
			
		||||
    ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
 | 
			
		||||
    samples = in->samples;
 | 
			
		||||
    if (ready == 0) {
 | 
			
		||||
        static const uint32_t silence[LINE_IN_SAMPLES];
 | 
			
		||||
        samples = silence;
 | 
			
		||||
        ready = LINE_IN_SAMPLES;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    num_samples = audio_MIN (ready, num_samples);
 | 
			
		||||
 | 
			
		||||
    if (hw->wpos + num_samples > hw->samples) {
 | 
			
		||||
        len[0] = hw->samples - hw->wpos;
 | 
			
		||||
        len[1] = num_samples - len[0];
 | 
			
		||||
    } else {
 | 
			
		||||
        len[0] = num_samples;
 | 
			
		||||
        len[1] = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
 | 
			
		||||
 | 
			
		||||
    if (len[1]) {
 | 
			
		||||
        hw->conv (hw->conv_buf, samples + len[0], len[1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hw->wpos = (hw->wpos + num_samples) % hw->samples;
 | 
			
		||||
 | 
			
		||||
    return num_samples;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int line_in_read (SWVoiceIn *sw, void *buf, int size)
 | 
			
		||||
{
 | 
			
		||||
    return audio_pcm_sw_read (sw, buf, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
 | 
			
		||||
{
 | 
			
		||||
    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
 | 
			
		||||
 | 
			
		||||
    switch (cmd) {
 | 
			
		||||
    case VOICE_ENABLE:
 | 
			
		||||
        if (in->active) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        in->active = 1;
 | 
			
		||||
        rate_start (&in->rate);
 | 
			
		||||
        spice_server_record_start (&in->sin);
 | 
			
		||||
        break;
 | 
			
		||||
    case VOICE_DISABLE:
 | 
			
		||||
        if (!in->active) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        in->active = 0;
 | 
			
		||||
        spice_server_record_stop (&in->sin);
 | 
			
		||||
        break;
 | 
			
		||||
    case VOICE_VOLUME:
 | 
			
		||||
        {
 | 
			
		||||
#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
 | 
			
		||||
            SWVoiceIn *sw;
 | 
			
		||||
            va_list ap;
 | 
			
		||||
            uint16_t vol[2];
 | 
			
		||||
 | 
			
		||||
            va_start (ap, cmd);
 | 
			
		||||
            sw = va_arg (ap, SWVoiceIn *);
 | 
			
		||||
            va_end (ap);
 | 
			
		||||
 | 
			
		||||
            vol[0] = sw->vol.l / ((1ULL << 16) + 1);
 | 
			
		||||
            vol[1] = sw->vol.r / ((1ULL << 16) + 1);
 | 
			
		||||
            spice_server_record_set_volume (&in->sin, 2, vol);
 | 
			
		||||
            spice_server_record_set_mute (&in->sin, sw->vol.mute);
 | 
			
		||||
#endif
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct audio_option audio_options[] = {
 | 
			
		||||
    { /* end of list */ },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct audio_pcm_ops audio_callbacks = {
 | 
			
		||||
    .init_out = line_out_init,
 | 
			
		||||
    .fini_out = line_out_fini,
 | 
			
		||||
    .run_out  = line_out_run,
 | 
			
		||||
    .write    = line_out_write,
 | 
			
		||||
    .ctl_out  = line_out_ctl,
 | 
			
		||||
 | 
			
		||||
    .init_in  = line_in_init,
 | 
			
		||||
    .fini_in  = line_in_fini,
 | 
			
		||||
    .run_in   = line_in_run,
 | 
			
		||||
    .read     = line_in_read,
 | 
			
		||||
    .ctl_in   = line_in_ctl,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct audio_driver spice_audio_driver = {
 | 
			
		||||
    .name           = "spice",
 | 
			
		||||
    .descr          = "spice audio driver",
 | 
			
		||||
    .options        = audio_options,
 | 
			
		||||
    .init           = spice_audio_init,
 | 
			
		||||
    .fini           = spice_audio_fini,
 | 
			
		||||
    .pcm_ops        = &audio_callbacks,
 | 
			
		||||
    .max_voices_out = 1,
 | 
			
		||||
    .max_voices_in  = 1,
 | 
			
		||||
    .voice_size_out = sizeof (SpiceVoiceOut),
 | 
			
		||||
    .voice_size_in  = sizeof (SpiceVoiceIn),
 | 
			
		||||
#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
 | 
			
		||||
    .ctl_caps       = VOICE_VOLUME_CAP
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void qemu_spice_audio_init (void)
 | 
			
		||||
{
 | 
			
		||||
    spice_audio_driver.can_be_default = 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
 | 
			
		||||
typedef struct WAVVoiceOut {
 | 
			
		||||
    HWVoiceOut hw;
 | 
			
		||||
    FILE *f;
 | 
			
		||||
    QEMUFile *f;
 | 
			
		||||
    int64_t old_ticks;
 | 
			
		||||
    void *pcm_buf;
 | 
			
		||||
    int total_samples;
 | 
			
		||||
@@ -52,7 +52,7 @@ static int wav_run_out (HWVoiceOut *hw, int live)
 | 
			
		||||
    int rpos, decr, samples;
 | 
			
		||||
    uint8_t *dst;
 | 
			
		||||
    struct st_sample *src;
 | 
			
		||||
    int64_t now = qemu_get_clock_ns (vm_clock);
 | 
			
		||||
    int64_t now = qemu_get_clock (vm_clock);
 | 
			
		||||
    int64_t ticks = now - wav->old_ticks;
 | 
			
		||||
    int64_t bytes =
 | 
			
		||||
        muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
 | 
			
		||||
@@ -76,10 +76,7 @@ static int wav_run_out (HWVoiceOut *hw, int live)
 | 
			
		||||
        dst = advance (wav->pcm_buf, rpos << hw->info.shift);
 | 
			
		||||
 | 
			
		||||
        hw->clip (dst, src, convert_samples);
 | 
			
		||||
        if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) {
 | 
			
		||||
            dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n",
 | 
			
		||||
                   convert_samples << hw->info.shift, strerror (errno));
 | 
			
		||||
        }
 | 
			
		||||
        qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
 | 
			
		||||
 | 
			
		||||
        rpos = (rpos + convert_samples) % hw->samples;
 | 
			
		||||
        samples -= convert_samples;
 | 
			
		||||
@@ -155,20 +152,16 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
 | 
			
		||||
    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
 | 
			
		||||
 | 
			
		||||
    wav->f = fopen (conf.wav_path, "wb");
 | 
			
		||||
    wav->f = qemu_fopen (conf.wav_path, "wb");
 | 
			
		||||
    if (!wav->f) {
 | 
			
		||||
        dolog ("Failed to open wave file `%s'\nReason: %s\n",
 | 
			
		||||
               conf.wav_path, strerror (errno));
 | 
			
		||||
        g_free (wav->pcm_buf);
 | 
			
		||||
        qemu_free (wav->pcm_buf);
 | 
			
		||||
        wav->pcm_buf = NULL;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
 | 
			
		||||
        dolog ("wav_init_out: failed to write header\nReason: %s\n",
 | 
			
		||||
               strerror(errno));
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -187,35 +180,16 @@ static void wav_fini_out (HWVoiceOut *hw)
 | 
			
		||||
    le_store (rlen, rifflen, 4);
 | 
			
		||||
    le_store (dlen, datalen, 4);
 | 
			
		||||
 | 
			
		||||
    if (fseek (wav->f, 4, SEEK_SET)) {
 | 
			
		||||
        dolog ("wav_fini_out: fseek to rlen failed\nReason: %s\n",
 | 
			
		||||
               strerror(errno));
 | 
			
		||||
        goto doclose;
 | 
			
		||||
    }
 | 
			
		||||
    if (fwrite (rlen, 4, 1, wav->f) != 1) {
 | 
			
		||||
        dolog ("wav_fini_out: failed to write rlen\nReason: %s\n",
 | 
			
		||||
               strerror (errno));
 | 
			
		||||
        goto doclose;
 | 
			
		||||
    }
 | 
			
		||||
    if (fseek (wav->f, 32, SEEK_CUR)) {
 | 
			
		||||
        dolog ("wav_fini_out: fseek to dlen failed\nReason: %s\n",
 | 
			
		||||
               strerror (errno));
 | 
			
		||||
        goto doclose;
 | 
			
		||||
    }
 | 
			
		||||
    if (fwrite (dlen, 4, 1, wav->f) != 1) {
 | 
			
		||||
        dolog ("wav_fini_out: failed to write dlen\nReaons: %s\n",
 | 
			
		||||
               strerror (errno));
 | 
			
		||||
        goto doclose;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_fseek (wav->f, 4, SEEK_SET);
 | 
			
		||||
    qemu_put_buffer (wav->f, rlen, 4);
 | 
			
		||||
 | 
			
		||||
 doclose:
 | 
			
		||||
    if (fclose (wav->f))  {
 | 
			
		||||
        dolog ("wav_fini_out: fclose %p failed\nReason: %s\n",
 | 
			
		||||
               wav->f, strerror (errno));
 | 
			
		||||
    }
 | 
			
		||||
    qemu_fseek (wav->f, 32, SEEK_CUR);
 | 
			
		||||
    qemu_put_buffer (wav->f, dlen, 4);
 | 
			
		||||
 | 
			
		||||
    qemu_fclose (wav->f);
 | 
			
		||||
    wav->f = NULL;
 | 
			
		||||
 | 
			
		||||
    g_free (wav->pcm_buf);
 | 
			
		||||
    qemu_free (wav->pcm_buf);
 | 
			
		||||
    wav->pcm_buf = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
#include "audio.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    FILE *f;
 | 
			
		||||
    QEMUFile *f;
 | 
			
		||||
    int bytes;
 | 
			
		||||
    char *path;
 | 
			
		||||
    int freq;
 | 
			
		||||
@@ -35,50 +35,27 @@ static void wav_destroy (void *opaque)
 | 
			
		||||
    uint8_t dlen[4];
 | 
			
		||||
    uint32_t datalen = wav->bytes;
 | 
			
		||||
    uint32_t rifflen = datalen + 36;
 | 
			
		||||
    Monitor *mon = cur_mon;
 | 
			
		||||
 | 
			
		||||
    if (wav->f) {
 | 
			
		||||
        le_store (rlen, rifflen, 4);
 | 
			
		||||
        le_store (dlen, datalen, 4);
 | 
			
		||||
 | 
			
		||||
        if (fseek (wav->f, 4, SEEK_SET)) {
 | 
			
		||||
            monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
 | 
			
		||||
                            strerror (errno));
 | 
			
		||||
            goto doclose;
 | 
			
		||||
        }
 | 
			
		||||
        if (fwrite (rlen, 4, 1, wav->f) != 1) {
 | 
			
		||||
            monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n",
 | 
			
		||||
                            strerror (errno));
 | 
			
		||||
            goto doclose;
 | 
			
		||||
        }
 | 
			
		||||
        if (fseek (wav->f, 32, SEEK_CUR)) {
 | 
			
		||||
            monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n",
 | 
			
		||||
                            strerror (errno));
 | 
			
		||||
            goto doclose;
 | 
			
		||||
        }
 | 
			
		||||
        if (fwrite (dlen, 1, 4, wav->f) != 4) {
 | 
			
		||||
            monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n",
 | 
			
		||||
                            strerror (errno));
 | 
			
		||||
            goto doclose;
 | 
			
		||||
        }
 | 
			
		||||
    doclose:
 | 
			
		||||
        if (fclose (wav->f)) {
 | 
			
		||||
            fprintf (stderr, "wav_destroy: fclose failed: %s",
 | 
			
		||||
                     strerror (errno));
 | 
			
		||||
        }
 | 
			
		||||
        qemu_fseek (wav->f, 4, SEEK_SET);
 | 
			
		||||
        qemu_put_buffer (wav->f, rlen, 4);
 | 
			
		||||
 | 
			
		||||
        qemu_fseek (wav->f, 32, SEEK_CUR);
 | 
			
		||||
        qemu_put_buffer (wav->f, dlen, 4);
 | 
			
		||||
        qemu_fclose (wav->f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free (wav->path);
 | 
			
		||||
    qemu_free (wav->path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wav_capture (void *opaque, void *buf, int size)
 | 
			
		||||
{
 | 
			
		||||
    WAVState *wav = opaque;
 | 
			
		||||
 | 
			
		||||
    if (fwrite (buf, size, 1, wav->f) != 1) {
 | 
			
		||||
        monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
 | 
			
		||||
                        strerror (errno));
 | 
			
		||||
    }
 | 
			
		||||
    qemu_put_buffer (wav->f, buf, size);
 | 
			
		||||
    wav->bytes += size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -94,7 +71,7 @@ static void wav_capture_info (void *opaque)
 | 
			
		||||
    WAVState *wav = opaque;
 | 
			
		||||
    char *path = wav->path;
 | 
			
		||||
 | 
			
		||||
    monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
 | 
			
		||||
    monitor_printf(cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
 | 
			
		||||
                   wav->freq, wav->bits, wav->nchannels,
 | 
			
		||||
                   path ? path : "<not available>", wav->bytes);
 | 
			
		||||
}
 | 
			
		||||
@@ -121,12 +98,12 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
 | 
			
		||||
    CaptureVoiceOut *cap;
 | 
			
		||||
 | 
			
		||||
    if (bits != 8 && bits != 16) {
 | 
			
		||||
        monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
 | 
			
		||||
        monitor_printf(mon, "incorrect bit count %d, must be 8 or 16\n", bits);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (nchannels != 1 && nchannels != 2) {
 | 
			
		||||
        monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
 | 
			
		||||
        monitor_printf(mon, "incorrect channel count %d, must be 1 or 2\n",
 | 
			
		||||
                       nchannels);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
@@ -143,7 +120,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
 | 
			
		||||
    ops.capture = wav_capture;
 | 
			
		||||
    ops.destroy = wav_destroy;
 | 
			
		||||
 | 
			
		||||
    wav = g_malloc0 (sizeof (*wav));
 | 
			
		||||
    wav = qemu_mallocz (sizeof (*wav));
 | 
			
		||||
 | 
			
		||||
    shift = bits16 + stereo;
 | 
			
		||||
    hdr[34] = bits16 ? 0x10 : 0x08;
 | 
			
		||||
@@ -153,42 +130,32 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
 | 
			
		||||
    le_store (hdr + 28, freq << shift, 4);
 | 
			
		||||
    le_store (hdr + 32, 1 << shift, 2);
 | 
			
		||||
 | 
			
		||||
    wav->f = fopen (path, "wb");
 | 
			
		||||
    wav->f = qemu_fopen (path, "wb");
 | 
			
		||||
    if (!wav->f) {
 | 
			
		||||
        monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
 | 
			
		||||
        monitor_printf(mon, "Failed to open wave file `%s'\nReason: %s\n",
 | 
			
		||||
                       path, strerror (errno));
 | 
			
		||||
        g_free (wav);
 | 
			
		||||
        qemu_free (wav);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    wav->path = g_strdup (path);
 | 
			
		||||
    wav->path = qemu_strdup (path);
 | 
			
		||||
    wav->bits = bits;
 | 
			
		||||
    wav->nchannels = nchannels;
 | 
			
		||||
    wav->freq = freq;
 | 
			
		||||
 | 
			
		||||
    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
 | 
			
		||||
        monitor_printf (mon, "Failed to write header\nReason: %s\n",
 | 
			
		||||
                        strerror (errno));
 | 
			
		||||
        goto error_free;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
 | 
			
		||||
 | 
			
		||||
    cap = AUD_add_capture (&as, &ops, wav);
 | 
			
		||||
    if (!cap) {
 | 
			
		||||
        monitor_printf (mon, "Failed to add audio capture\n");
 | 
			
		||||
        goto error_free;
 | 
			
		||||
        monitor_printf(mon, "Failed to add audio capture\n");
 | 
			
		||||
        qemu_free (wav->path);
 | 
			
		||||
        qemu_fclose (wav->f);
 | 
			
		||||
        qemu_free (wav);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    wav->cap = cap;
 | 
			
		||||
    s->opaque = wav;
 | 
			
		||||
    s->ops = wav_capture_ops;
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
error_free:
 | 
			
		||||
    g_free (wav->path);
 | 
			
		||||
    if (fclose (wav->f)) {
 | 
			
		||||
        monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
 | 
			
		||||
                        strerror (errno));
 | 
			
		||||
    }
 | 
			
		||||
    g_free (wav);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -222,9 +222,9 @@ static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
 err4:
 | 
			
		||||
    g_free (wave->pcm_buf);
 | 
			
		||||
    qemu_free (wave->pcm_buf);
 | 
			
		||||
 err3:
 | 
			
		||||
    g_free (wave->hdrs);
 | 
			
		||||
    qemu_free (wave->hdrs);
 | 
			
		||||
 err2:
 | 
			
		||||
    winwave_anal_close_out (wave);
 | 
			
		||||
 err1:
 | 
			
		||||
@@ -310,10 +310,10 @@ static void winwave_fini_out (HWVoiceOut *hw)
 | 
			
		||||
        wave->event = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free (wave->pcm_buf);
 | 
			
		||||
    qemu_free (wave->pcm_buf);
 | 
			
		||||
    wave->pcm_buf = NULL;
 | 
			
		||||
 | 
			
		||||
    g_free (wave->hdrs);
 | 
			
		||||
    qemu_free (wave->hdrs);
 | 
			
		||||
    wave->hdrs = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -511,9 +511,9 @@ static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
 err4:
 | 
			
		||||
    g_free (wave->pcm_buf);
 | 
			
		||||
    qemu_free (wave->pcm_buf);
 | 
			
		||||
 err3:
 | 
			
		||||
    g_free (wave->hdrs);
 | 
			
		||||
    qemu_free (wave->hdrs);
 | 
			
		||||
 err2:
 | 
			
		||||
    winwave_anal_close_in (wave);
 | 
			
		||||
 err1:
 | 
			
		||||
@@ -550,10 +550,10 @@ static void winwave_fini_in (HWVoiceIn *hw)
 | 
			
		||||
        wave->event = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free (wave->pcm_buf);
 | 
			
		||||
    qemu_free (wave->pcm_buf);
 | 
			
		||||
    wave->pcm_buf = NULL;
 | 
			
		||||
 | 
			
		||||
    g_free (wave->hdrs);
 | 
			
		||||
    qemu_free (wave->hdrs);
 | 
			
		||||
    wave->hdrs = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -581,7 +581,8 @@ static int winwave_run_in (HWVoiceIn *hw)
 | 
			
		||||
        int conv = audio_MIN (left, decr);
 | 
			
		||||
        hw->conv (hw->conv_buf + hw->wpos,
 | 
			
		||||
                  advance (wave->pcm_buf, wave->rpos << hw->info.shift),
 | 
			
		||||
                  conv);
 | 
			
		||||
                  conv,
 | 
			
		||||
                  &nominal_volume);
 | 
			
		||||
 | 
			
		||||
        wave->rpos = (wave->rpos + conv) % hw->samples;
 | 
			
		||||
        hw->wpos = (hw->wpos + conv) % hw->samples;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										118
									
								
								balloon.c
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								balloon.c
									
									
									
									
									
								
							@@ -1,118 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Generic Balloon handlers and management
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2003-2008 Fabrice Bellard
 | 
			
		||||
 * Copyright (C) 2011 Red Hat, Inc.
 | 
			
		||||
 * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "monitor.h"
 | 
			
		||||
#include "cpu-common.h"
 | 
			
		||||
#include "kvm.h"
 | 
			
		||||
#include "balloon.h"
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
#include "qmp-commands.h"
 | 
			
		||||
 | 
			
		||||
static QEMUBalloonEvent *balloon_event_fn;
 | 
			
		||||
static QEMUBalloonStatus *balloon_stat_fn;
 | 
			
		||||
static void *balloon_opaque;
 | 
			
		||||
 | 
			
		||||
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
 | 
			
		||||
                             QEMUBalloonStatus *stat_func, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    if (balloon_event_fn || balloon_stat_fn || balloon_opaque) {
 | 
			
		||||
        /* We're already registered one balloon handler.  How many can
 | 
			
		||||
         * a guest really have?
 | 
			
		||||
         */
 | 
			
		||||
        error_report("Another balloon device already registered");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    balloon_event_fn = event_func;
 | 
			
		||||
    balloon_stat_fn = stat_func;
 | 
			
		||||
    balloon_opaque = opaque;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_remove_balloon_handler(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    if (balloon_opaque != opaque) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    balloon_event_fn = NULL;
 | 
			
		||||
    balloon_stat_fn = NULL;
 | 
			
		||||
    balloon_opaque = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_balloon(ram_addr_t target)
 | 
			
		||||
{
 | 
			
		||||
    if (!balloon_event_fn) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    trace_balloon_event(balloon_opaque, target);
 | 
			
		||||
    balloon_event_fn(balloon_opaque, target);
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_balloon_status(BalloonInfo *info)
 | 
			
		||||
{
 | 
			
		||||
    if (!balloon_stat_fn) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    balloon_stat_fn(balloon_opaque, info);
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BalloonInfo *qmp_query_balloon(Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    BalloonInfo *info;
 | 
			
		||||
 | 
			
		||||
    if (kvm_enabled() && !kvm_has_sync_mmu()) {
 | 
			
		||||
        error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info = g_malloc0(sizeof(*info));
 | 
			
		||||
 | 
			
		||||
    if (qemu_balloon_status(info) == 0) {
 | 
			
		||||
        error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
 | 
			
		||||
        qapi_free_BalloonInfo(info);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_balloon(int64_t value, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    if (kvm_enabled() && !kvm_has_sync_mmu()) {
 | 
			
		||||
        error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (value <= 0) {
 | 
			
		||||
        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "target", "a size");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (qemu_balloon(value) == 0) {
 | 
			
		||||
        error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								balloon.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								balloon.h
									
									
									
									
									
								
							@@ -14,14 +14,14 @@
 | 
			
		||||
#ifndef _QEMU_BALLOON_H
 | 
			
		||||
#define _QEMU_BALLOON_H
 | 
			
		||||
 | 
			
		||||
#include "monitor.h"
 | 
			
		||||
#include "qapi-types.h"
 | 
			
		||||
#include "cpu-defs.h"
 | 
			
		||||
 | 
			
		||||
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
 | 
			
		||||
typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
 | 
			
		||||
typedef ram_addr_t (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
 | 
			
		||||
 | 
			
		||||
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
 | 
			
		||||
			     QEMUBalloonStatus *stat_func, void *opaque);
 | 
			
		||||
void qemu_remove_balloon_handler(void *opaque);
 | 
			
		||||
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
 | 
			
		||||
 | 
			
		||||
void qemu_balloon(ram_addr_t target);
 | 
			
		||||
 | 
			
		||||
ram_addr_t qemu_balloon_status(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										256
									
								
								bitmap.c
									
									
									
									
									
								
							
							
						
						
									
										256
									
								
								bitmap.c
									
									
									
									
									
								
							@@ -1,256 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Bitmap Module
 | 
			
		||||
 *
 | 
			
		||||
 * Stolen from linux/src/lib/bitmap.c
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2010 Corentin Chary
 | 
			
		||||
 *
 | 
			
		||||
 * This source code is licensed under the GNU General Public License,
 | 
			
		||||
 * Version 2.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "bitops.h"
 | 
			
		||||
#include "bitmap.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * bitmaps provide an array of bits, implemented using an an
 | 
			
		||||
 * array of unsigned longs.  The number of valid bits in a
 | 
			
		||||
 * given bitmap does _not_ need to be an exact multiple of
 | 
			
		||||
 * BITS_PER_LONG.
 | 
			
		||||
 *
 | 
			
		||||
 * The possible unused bits in the last, partially used word
 | 
			
		||||
 * of a bitmap are 'don't care'.  The implementation makes
 | 
			
		||||
 * no particular effort to keep them zero.  It ensures that
 | 
			
		||||
 * their value will not affect the results of any operation.
 | 
			
		||||
 * The bitmap operations that return Boolean (bitmap_empty,
 | 
			
		||||
 * for example) or scalar (bitmap_weight, for example) results
 | 
			
		||||
 * carefully filter out these unused bits from impacting their
 | 
			
		||||
 * results.
 | 
			
		||||
 *
 | 
			
		||||
 * These operations actually hold to a slightly stronger rule:
 | 
			
		||||
 * if you don't input any bitmaps to these ops that have some
 | 
			
		||||
 * unused bits set, then they won't output any set unused bits
 | 
			
		||||
 * in output bitmaps.
 | 
			
		||||
 *
 | 
			
		||||
 * The byte ordering of bitmaps is more natural on little
 | 
			
		||||
 * endian architectures.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int slow_bitmap_empty(const unsigned long *bitmap, int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k, lim = bits/BITS_PER_LONG;
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < lim; ++k) {
 | 
			
		||||
        if (bitmap[k]) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (bits % BITS_PER_LONG) {
 | 
			
		||||
        if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int slow_bitmap_full(const unsigned long *bitmap, int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k, lim = bits/BITS_PER_LONG;
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < lim; ++k) {
 | 
			
		||||
        if (~bitmap[k]) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bits % BITS_PER_LONG) {
 | 
			
		||||
        if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int slow_bitmap_equal(const unsigned long *bitmap1,
 | 
			
		||||
                      const unsigned long *bitmap2, int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k, lim = bits/BITS_PER_LONG;
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < lim; ++k) {
 | 
			
		||||
        if (bitmap1[k] != bitmap2[k]) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bits % BITS_PER_LONG) {
 | 
			
		||||
        if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
 | 
			
		||||
                            int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k, lim = bits/BITS_PER_LONG;
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < lim; ++k) {
 | 
			
		||||
        dst[k] = ~src[k];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bits % BITS_PER_LONG) {
 | 
			
		||||
        dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
 | 
			
		||||
                    const unsigned long *bitmap2, int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k;
 | 
			
		||||
    int nr = BITS_TO_LONGS(bits);
 | 
			
		||||
    unsigned long result = 0;
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < nr; k++) {
 | 
			
		||||
        result |= (dst[k] = bitmap1[k] & bitmap2[k]);
 | 
			
		||||
    }
 | 
			
		||||
    return result != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
 | 
			
		||||
                    const unsigned long *bitmap2, int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k;
 | 
			
		||||
    int nr = BITS_TO_LONGS(bits);
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < nr; k++) {
 | 
			
		||||
        dst[k] = bitmap1[k] | bitmap2[k];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
 | 
			
		||||
                     const unsigned long *bitmap2, int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k;
 | 
			
		||||
    int nr = BITS_TO_LONGS(bits);
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < nr; k++) {
 | 
			
		||||
        dst[k] = bitmap1[k] ^ bitmap2[k];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
 | 
			
		||||
                       const unsigned long *bitmap2, int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k;
 | 
			
		||||
    int nr = BITS_TO_LONGS(bits);
 | 
			
		||||
    unsigned long result = 0;
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < nr; k++) {
 | 
			
		||||
        result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
 | 
			
		||||
    }
 | 
			
		||||
    return result != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
 | 
			
		||||
 | 
			
		||||
void bitmap_set(unsigned long *map, int start, int nr)
 | 
			
		||||
{
 | 
			
		||||
    unsigned long *p = map + BIT_WORD(start);
 | 
			
		||||
    const int size = start + nr;
 | 
			
		||||
    int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
 | 
			
		||||
    unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
 | 
			
		||||
 | 
			
		||||
    while (nr - bits_to_set >= 0) {
 | 
			
		||||
        *p |= mask_to_set;
 | 
			
		||||
        nr -= bits_to_set;
 | 
			
		||||
        bits_to_set = BITS_PER_LONG;
 | 
			
		||||
        mask_to_set = ~0UL;
 | 
			
		||||
        p++;
 | 
			
		||||
    }
 | 
			
		||||
    if (nr) {
 | 
			
		||||
        mask_to_set &= BITMAP_LAST_WORD_MASK(size);
 | 
			
		||||
        *p |= mask_to_set;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bitmap_clear(unsigned long *map, int start, int nr)
 | 
			
		||||
{
 | 
			
		||||
    unsigned long *p = map + BIT_WORD(start);
 | 
			
		||||
    const int size = start + nr;
 | 
			
		||||
    int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
 | 
			
		||||
    unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
 | 
			
		||||
 | 
			
		||||
    while (nr - bits_to_clear >= 0) {
 | 
			
		||||
        *p &= ~mask_to_clear;
 | 
			
		||||
        nr -= bits_to_clear;
 | 
			
		||||
        bits_to_clear = BITS_PER_LONG;
 | 
			
		||||
        mask_to_clear = ~0UL;
 | 
			
		||||
        p++;
 | 
			
		||||
    }
 | 
			
		||||
    if (nr) {
 | 
			
		||||
        mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
 | 
			
		||||
        *p &= ~mask_to_clear;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * bitmap_find_next_zero_area - find a contiguous aligned zero area
 | 
			
		||||
 * @map: The address to base the search on
 | 
			
		||||
 * @size: The bitmap size in bits
 | 
			
		||||
 * @start: The bitnumber to start searching at
 | 
			
		||||
 * @nr: The number of zeroed bits we're looking for
 | 
			
		||||
 * @align_mask: Alignment mask for zero area
 | 
			
		||||
 *
 | 
			
		||||
 * The @align_mask should be one less than a power of 2; the effect is that
 | 
			
		||||
 * the bit offset of all zero areas this function finds is multiples of that
 | 
			
		||||
 * power of 2. A @align_mask of 0 means no alignment is required.
 | 
			
		||||
 */
 | 
			
		||||
unsigned long bitmap_find_next_zero_area(unsigned long *map,
 | 
			
		||||
					 unsigned long size,
 | 
			
		||||
					 unsigned long start,
 | 
			
		||||
					 unsigned int nr,
 | 
			
		||||
					 unsigned long align_mask)
 | 
			
		||||
{
 | 
			
		||||
    unsigned long index, end, i;
 | 
			
		||||
again:
 | 
			
		||||
    index = find_next_zero_bit(map, size, start);
 | 
			
		||||
 | 
			
		||||
    /* Align allocation */
 | 
			
		||||
    index = ALIGN_MASK(index, align_mask);
 | 
			
		||||
 | 
			
		||||
    end = index + nr;
 | 
			
		||||
    if (end > size) {
 | 
			
		||||
        return end;
 | 
			
		||||
    }
 | 
			
		||||
    i = find_next_bit(map, end, index);
 | 
			
		||||
    if (i < end) {
 | 
			
		||||
        start = i + 1;
 | 
			
		||||
        goto again;
 | 
			
		||||
    }
 | 
			
		||||
    return index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int slow_bitmap_intersects(const unsigned long *bitmap1,
 | 
			
		||||
                           const unsigned long *bitmap2, int bits)
 | 
			
		||||
{
 | 
			
		||||
    int k, lim = bits/BITS_PER_LONG;
 | 
			
		||||
 | 
			
		||||
    for (k = 0; k < lim; ++k) {
 | 
			
		||||
        if (bitmap1[k] & bitmap2[k]) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bits % BITS_PER_LONG) {
 | 
			
		||||
        if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										222
									
								
								bitmap.h
									
									
									
									
									
								
							
							
						
						
									
										222
									
								
								bitmap.h
									
									
									
									
									
								
							@@ -1,222 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Bitmap Module
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Mostly inspired by (stolen from) linux/bitmap.h and linux/bitops.h
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef BITMAP_H
 | 
			
		||||
#define BITMAP_H
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "bitops.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The available bitmap operations and their rough meaning in the
 | 
			
		||||
 * case that the bitmap is a single unsigned long are thus:
 | 
			
		||||
 *
 | 
			
		||||
 * Note that nbits should be always a compile time evaluable constant.
 | 
			
		||||
 * Otherwise many inlines will generate horrible code.
 | 
			
		||||
 *
 | 
			
		||||
 * bitmap_zero(dst, nbits)			*dst = 0UL
 | 
			
		||||
 * bitmap_fill(dst, nbits)			*dst = ~0UL
 | 
			
		||||
 * bitmap_copy(dst, src, nbits)			*dst = *src
 | 
			
		||||
 * bitmap_and(dst, src1, src2, nbits)		*dst = *src1 & *src2
 | 
			
		||||
 * bitmap_or(dst, src1, src2, nbits)		*dst = *src1 | *src2
 | 
			
		||||
 * bitmap_xor(dst, src1, src2, nbits)		*dst = *src1 ^ *src2
 | 
			
		||||
 * bitmap_andnot(dst, src1, src2, nbits)	*dst = *src1 & ~(*src2)
 | 
			
		||||
 * bitmap_complement(dst, src, nbits)		*dst = ~(*src)
 | 
			
		||||
 * bitmap_equal(src1, src2, nbits)		Are *src1 and *src2 equal?
 | 
			
		||||
 * bitmap_intersects(src1, src2, nbits) 	Do *src1 and *src2 overlap?
 | 
			
		||||
 * bitmap_empty(src, nbits)			Are all bits zero in *src?
 | 
			
		||||
 * bitmap_full(src, nbits)			Are all bits set in *src?
 | 
			
		||||
 * bitmap_set(dst, pos, nbits)			Set specified bit area
 | 
			
		||||
 * bitmap_clear(dst, pos, nbits)		Clear specified bit area
 | 
			
		||||
 * bitmap_find_next_zero_area(buf, len, pos, n, mask)	Find bit free area
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Also the following operations apply to bitmaps.
 | 
			
		||||
 *
 | 
			
		||||
 * set_bit(bit, addr)			*addr |= bit
 | 
			
		||||
 * clear_bit(bit, addr)			*addr &= ~bit
 | 
			
		||||
 * change_bit(bit, addr)		*addr ^= bit
 | 
			
		||||
 * test_bit(bit, addr)			Is bit set in *addr?
 | 
			
		||||
 * test_and_set_bit(bit, addr)		Set bit and return old value
 | 
			
		||||
 * test_and_clear_bit(bit, addr)	Clear bit and return old value
 | 
			
		||||
 * test_and_change_bit(bit, addr)	Change bit and return old value
 | 
			
		||||
 * find_first_zero_bit(addr, nbits)	Position first zero bit in *addr
 | 
			
		||||
 * find_first_bit(addr, nbits)		Position first set bit in *addr
 | 
			
		||||
 * find_next_zero_bit(addr, nbits, bit)	Position next zero bit in *addr >= bit
 | 
			
		||||
 * find_next_bit(addr, nbits, bit)	Position next set bit in *addr >= bit
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define BITMAP_LAST_WORD_MASK(nbits)                                    \
 | 
			
		||||
    (                                                                   \
 | 
			
		||||
        ((nbits) % BITS_PER_LONG) ?                                     \
 | 
			
		||||
        (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL                       \
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
#define DECLARE_BITMAP(name,bits)                  \
 | 
			
		||||
	unsigned long name[BITS_TO_LONGS(bits)]
 | 
			
		||||
 | 
			
		||||
#define small_nbits(nbits)                      \
 | 
			
		||||
	((nbits) <= BITS_PER_LONG)
 | 
			
		||||
 | 
			
		||||
int slow_bitmap_empty(const unsigned long *bitmap, int bits);
 | 
			
		||||
int slow_bitmap_full(const unsigned long *bitmap, int bits);
 | 
			
		||||
int slow_bitmap_equal(const unsigned long *bitmap1,
 | 
			
		||||
                   const unsigned long *bitmap2, int bits);
 | 
			
		||||
void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
 | 
			
		||||
                         int bits);
 | 
			
		||||
void slow_bitmap_shift_right(unsigned long *dst,
 | 
			
		||||
                          const unsigned long *src, int shift, int bits);
 | 
			
		||||
void slow_bitmap_shift_left(unsigned long *dst,
 | 
			
		||||
                         const unsigned long *src, int shift, int bits);
 | 
			
		||||
int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
 | 
			
		||||
                 const unsigned long *bitmap2, int bits);
 | 
			
		||||
void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
 | 
			
		||||
                 const unsigned long *bitmap2, int bits);
 | 
			
		||||
void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
 | 
			
		||||
                  const unsigned long *bitmap2, int bits);
 | 
			
		||||
int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
 | 
			
		||||
                    const unsigned long *bitmap2, int bits);
 | 
			
		||||
int slow_bitmap_intersects(const unsigned long *bitmap1,
 | 
			
		||||
			const unsigned long *bitmap2, int bits);
 | 
			
		||||
 | 
			
		||||
static inline unsigned long *bitmap_new(int nbits)
 | 
			
		||||
{
 | 
			
		||||
    int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
 | 
			
		||||
    return g_malloc0(len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bitmap_zero(unsigned long *dst, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        *dst = 0UL;
 | 
			
		||||
    } else {
 | 
			
		||||
        int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
 | 
			
		||||
        memset(dst, 0, len);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bitmap_fill(unsigned long *dst, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    size_t nlongs = BITS_TO_LONGS(nbits);
 | 
			
		||||
    if (!small_nbits(nbits)) {
 | 
			
		||||
        int len = (nlongs - 1) * sizeof(unsigned long);
 | 
			
		||||
        memset(dst, 0xff,  len);
 | 
			
		||||
    }
 | 
			
		||||
    dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bitmap_copy(unsigned long *dst, const unsigned long *src,
 | 
			
		||||
                               int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        *dst = *src;
 | 
			
		||||
    } else {
 | 
			
		||||
        int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
 | 
			
		||||
        memcpy(dst, src, len);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bitmap_and(unsigned long *dst, const unsigned long *src1,
 | 
			
		||||
                             const unsigned long *src2, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        return (*dst = *src1 & *src2) != 0;
 | 
			
		||||
    }
 | 
			
		||||
    return slow_bitmap_and(dst, src1, src2, nbits);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
 | 
			
		||||
			const unsigned long *src2, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        *dst = *src1 | *src2;
 | 
			
		||||
    } else {
 | 
			
		||||
        slow_bitmap_or(dst, src1, src2, nbits);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
 | 
			
		||||
			const unsigned long *src2, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        *dst = *src1 ^ *src2;
 | 
			
		||||
    } else {
 | 
			
		||||
        slow_bitmap_xor(dst, src1, src2, nbits);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bitmap_andnot(unsigned long *dst, const unsigned long *src1,
 | 
			
		||||
			const unsigned long *src2, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        return (*dst = *src1 & ~(*src2)) != 0;
 | 
			
		||||
    }
 | 
			
		||||
    return slow_bitmap_andnot(dst, src1, src2, nbits);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bitmap_complement(unsigned long *dst, const unsigned long *src,
 | 
			
		||||
			int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        *dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits);
 | 
			
		||||
    } else {
 | 
			
		||||
        slow_bitmap_complement(dst, src, nbits);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bitmap_equal(const unsigned long *src1,
 | 
			
		||||
			const unsigned long *src2, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
 | 
			
		||||
    } else {
 | 
			
		||||
        return slow_bitmap_equal(src1, src2, nbits);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bitmap_empty(const unsigned long *src, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
 | 
			
		||||
    } else {
 | 
			
		||||
        return slow_bitmap_empty(src, nbits);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bitmap_full(const unsigned long *src, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
 | 
			
		||||
    } else {
 | 
			
		||||
        return slow_bitmap_full(src, nbits);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bitmap_intersects(const unsigned long *src1,
 | 
			
		||||
			const unsigned long *src2, int nbits)
 | 
			
		||||
{
 | 
			
		||||
    if (small_nbits(nbits)) {
 | 
			
		||||
        return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        return slow_bitmap_intersects(src1, src2, nbits);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bitmap_set(unsigned long *map, int i, int len);
 | 
			
		||||
void bitmap_clear(unsigned long *map, int start, int nr);
 | 
			
		||||
unsigned long bitmap_find_next_zero_area(unsigned long *map,
 | 
			
		||||
					 unsigned long size,
 | 
			
		||||
					 unsigned long start,
 | 
			
		||||
					 unsigned int nr,
 | 
			
		||||
					 unsigned long align_mask);
 | 
			
		||||
 | 
			
		||||
#endif /* BITMAP_H */
 | 
			
		||||
							
								
								
									
										142
									
								
								bitops.c
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								bitops.c
									
									
									
									
									
								
							@@ -1,142 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
 | 
			
		||||
 * Written by David Howells (dhowells@redhat.com)
 | 
			
		||||
 * Copyright (C) 2008 IBM Corporation
 | 
			
		||||
 * Written by Rusty Russell <rusty@rustcorp.com.au>
 | 
			
		||||
 * (Inspired by David Howell's find_next_bit implementation)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version
 | 
			
		||||
 * 2 of the License, or (at your option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "bitops.h"
 | 
			
		||||
 | 
			
		||||
#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Find the next set bit in a memory region.
 | 
			
		||||
 */
 | 
			
		||||
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
 | 
			
		||||
			    unsigned long offset)
 | 
			
		||||
{
 | 
			
		||||
    const unsigned long *p = addr + BITOP_WORD(offset);
 | 
			
		||||
    unsigned long result = offset & ~(BITS_PER_LONG-1);
 | 
			
		||||
    unsigned long tmp;
 | 
			
		||||
 | 
			
		||||
    if (offset >= size) {
 | 
			
		||||
        return size;
 | 
			
		||||
    }
 | 
			
		||||
    size -= result;
 | 
			
		||||
    offset %= BITS_PER_LONG;
 | 
			
		||||
    if (offset) {
 | 
			
		||||
        tmp = *(p++);
 | 
			
		||||
        tmp &= (~0UL << offset);
 | 
			
		||||
        if (size < BITS_PER_LONG) {
 | 
			
		||||
            goto found_first;
 | 
			
		||||
        }
 | 
			
		||||
        if (tmp) {
 | 
			
		||||
            goto found_middle;
 | 
			
		||||
        }
 | 
			
		||||
        size -= BITS_PER_LONG;
 | 
			
		||||
        result += BITS_PER_LONG;
 | 
			
		||||
    }
 | 
			
		||||
    while (size & ~(BITS_PER_LONG-1)) {
 | 
			
		||||
        if ((tmp = *(p++))) {
 | 
			
		||||
            goto found_middle;
 | 
			
		||||
        }
 | 
			
		||||
        result += BITS_PER_LONG;
 | 
			
		||||
        size -= BITS_PER_LONG;
 | 
			
		||||
    }
 | 
			
		||||
    if (!size) {
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
    tmp = *p;
 | 
			
		||||
 | 
			
		||||
found_first:
 | 
			
		||||
    tmp &= (~0UL >> (BITS_PER_LONG - size));
 | 
			
		||||
    if (tmp == 0UL) {		/* Are any bits set? */
 | 
			
		||||
        return result + size;	/* Nope. */
 | 
			
		||||
    }
 | 
			
		||||
found_middle:
 | 
			
		||||
    return result + bitops_ffsl(tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This implementation of find_{first,next}_zero_bit was stolen from
 | 
			
		||||
 * Linus' asm-alpha/bitops.h.
 | 
			
		||||
 */
 | 
			
		||||
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
 | 
			
		||||
				 unsigned long offset)
 | 
			
		||||
{
 | 
			
		||||
    const unsigned long *p = addr + BITOP_WORD(offset);
 | 
			
		||||
    unsigned long result = offset & ~(BITS_PER_LONG-1);
 | 
			
		||||
    unsigned long tmp;
 | 
			
		||||
 | 
			
		||||
    if (offset >= size) {
 | 
			
		||||
        return size;
 | 
			
		||||
    }
 | 
			
		||||
    size -= result;
 | 
			
		||||
    offset %= BITS_PER_LONG;
 | 
			
		||||
    if (offset) {
 | 
			
		||||
        tmp = *(p++);
 | 
			
		||||
        tmp |= ~0UL >> (BITS_PER_LONG - offset);
 | 
			
		||||
        if (size < BITS_PER_LONG) {
 | 
			
		||||
            goto found_first;
 | 
			
		||||
        }
 | 
			
		||||
        if (~tmp) {
 | 
			
		||||
            goto found_middle;
 | 
			
		||||
        }
 | 
			
		||||
        size -= BITS_PER_LONG;
 | 
			
		||||
        result += BITS_PER_LONG;
 | 
			
		||||
    }
 | 
			
		||||
    while (size & ~(BITS_PER_LONG-1)) {
 | 
			
		||||
        if (~(tmp = *(p++))) {
 | 
			
		||||
            goto found_middle;
 | 
			
		||||
        }
 | 
			
		||||
        result += BITS_PER_LONG;
 | 
			
		||||
        size -= BITS_PER_LONG;
 | 
			
		||||
    }
 | 
			
		||||
    if (!size) {
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
    tmp = *p;
 | 
			
		||||
 | 
			
		||||
found_first:
 | 
			
		||||
    tmp |= ~0UL << size;
 | 
			
		||||
    if (tmp == ~0UL) {	/* Are any bits zero? */
 | 
			
		||||
        return result + size;	/* Nope. */
 | 
			
		||||
    }
 | 
			
		||||
found_middle:
 | 
			
		||||
    return result + ffz(tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
 | 
			
		||||
{
 | 
			
		||||
    unsigned long words;
 | 
			
		||||
    unsigned long tmp;
 | 
			
		||||
 | 
			
		||||
    /* Start at final word. */
 | 
			
		||||
    words = size / BITS_PER_LONG;
 | 
			
		||||
 | 
			
		||||
    /* Partial final word? */
 | 
			
		||||
    if (size & (BITS_PER_LONG-1)) {
 | 
			
		||||
        tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
 | 
			
		||||
                                       - (size & (BITS_PER_LONG-1)))));
 | 
			
		||||
        if (tmp) {
 | 
			
		||||
            goto found;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (words) {
 | 
			
		||||
        tmp = addr[--words];
 | 
			
		||||
        if (tmp) {
 | 
			
		||||
        found:
 | 
			
		||||
            return words * BITS_PER_LONG + bitops_flsl(tmp);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Not found */
 | 
			
		||||
    return size;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										272
									
								
								bitops.h
									
									
									
									
									
								
							
							
						
						
									
										272
									
								
								bitops.h
									
									
									
									
									
								
							@@ -1,272 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Bitops Module
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Mostly inspired by (stolen from) linux/bitmap.h and linux/bitops.h
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef BITOPS_H
 | 
			
		||||
#define BITOPS_H
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
 | 
			
		||||
#define BITS_PER_BYTE           CHAR_BIT
 | 
			
		||||
#define BITS_PER_LONG           (sizeof (unsigned long) * BITS_PER_BYTE)
 | 
			
		||||
 | 
			
		||||
#define BIT(nr)			(1UL << (nr))
 | 
			
		||||
#define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
 | 
			
		||||
#define BIT_WORD(nr)		((nr) / BITS_PER_LONG)
 | 
			
		||||
#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * bitops_ffs - find first bit in word.
 | 
			
		||||
 * @word: The word to search
 | 
			
		||||
 *
 | 
			
		||||
 * Undefined if no bit exists, so code should check against 0 first.
 | 
			
		||||
 */
 | 
			
		||||
static unsigned long bitops_ffsl(unsigned long word)
 | 
			
		||||
{
 | 
			
		||||
	int num = 0;
 | 
			
		||||
 | 
			
		||||
#if LONG_MAX > 0x7FFFFFFF
 | 
			
		||||
	if ((word & 0xffffffff) == 0) {
 | 
			
		||||
		num += 32;
 | 
			
		||||
		word >>= 32;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	if ((word & 0xffff) == 0) {
 | 
			
		||||
		num += 16;
 | 
			
		||||
		word >>= 16;
 | 
			
		||||
	}
 | 
			
		||||
	if ((word & 0xff) == 0) {
 | 
			
		||||
		num += 8;
 | 
			
		||||
		word >>= 8;
 | 
			
		||||
	}
 | 
			
		||||
	if ((word & 0xf) == 0) {
 | 
			
		||||
		num += 4;
 | 
			
		||||
		word >>= 4;
 | 
			
		||||
	}
 | 
			
		||||
	if ((word & 0x3) == 0) {
 | 
			
		||||
		num += 2;
 | 
			
		||||
		word >>= 2;
 | 
			
		||||
	}
 | 
			
		||||
	if ((word & 0x1) == 0) {
 | 
			
		||||
		num += 1;
 | 
			
		||||
        }
 | 
			
		||||
	return num;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * bitops_fls - find last (most-significant) set bit in a long word
 | 
			
		||||
 * @word: the word to search
 | 
			
		||||
 *
 | 
			
		||||
 * Undefined if no set bit exists, so code should check against 0 first.
 | 
			
		||||
 */
 | 
			
		||||
static inline unsigned long bitops_flsl(unsigned long word)
 | 
			
		||||
{
 | 
			
		||||
	int num = BITS_PER_LONG - 1;
 | 
			
		||||
 | 
			
		||||
#if LONG_MAX > 0x7FFFFFFF
 | 
			
		||||
	if (!(word & (~0ul << 32))) {
 | 
			
		||||
		num -= 32;
 | 
			
		||||
		word <<= 32;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
 | 
			
		||||
		num -= 16;
 | 
			
		||||
		word <<= 16;
 | 
			
		||||
	}
 | 
			
		||||
	if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
 | 
			
		||||
		num -= 8;
 | 
			
		||||
		word <<= 8;
 | 
			
		||||
	}
 | 
			
		||||
	if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
 | 
			
		||||
		num -= 4;
 | 
			
		||||
		word <<= 4;
 | 
			
		||||
	}
 | 
			
		||||
	if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
 | 
			
		||||
		num -= 2;
 | 
			
		||||
 | 
			
		||||
		word <<= 2;
 | 
			
		||||
	}
 | 
			
		||||
	if (!(word & (~0ul << (BITS_PER_LONG-1))))
 | 
			
		||||
		num -= 1;
 | 
			
		||||
	return num;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ffz - find first zero in word.
 | 
			
		||||
 * @word: The word to search
 | 
			
		||||
 *
 | 
			
		||||
 * Undefined if no zero exists, so code should check against ~0UL first.
 | 
			
		||||
 */
 | 
			
		||||
static inline unsigned long ffz(unsigned long word)
 | 
			
		||||
{
 | 
			
		||||
    return bitops_ffsl(~word);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * set_bit - Set a bit in memory
 | 
			
		||||
 * @nr: the bit to set
 | 
			
		||||
 * @addr: the address to start counting from
 | 
			
		||||
 */
 | 
			
		||||
static inline void set_bit(int nr, volatile unsigned long *addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mask = BIT_MASK(nr);
 | 
			
		||||
	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
 | 
			
		||||
 | 
			
		||||
	*p  |= mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * clear_bit - Clears a bit in memory
 | 
			
		||||
 * @nr: Bit to clear
 | 
			
		||||
 * @addr: Address to start counting from
 | 
			
		||||
 */
 | 
			
		||||
static inline void clear_bit(int nr, volatile unsigned long *addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mask = BIT_MASK(nr);
 | 
			
		||||
	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
 | 
			
		||||
 | 
			
		||||
	*p &= ~mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * change_bit - Toggle a bit in memory
 | 
			
		||||
 * @nr: Bit to change
 | 
			
		||||
 * @addr: Address to start counting from
 | 
			
		||||
 */
 | 
			
		||||
static inline void change_bit(int nr, volatile unsigned long *addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mask = BIT_MASK(nr);
 | 
			
		||||
	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
 | 
			
		||||
 | 
			
		||||
	*p ^= mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * test_and_set_bit - Set a bit and return its old value
 | 
			
		||||
 * @nr: Bit to set
 | 
			
		||||
 * @addr: Address to count from
 | 
			
		||||
 */
 | 
			
		||||
static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mask = BIT_MASK(nr);
 | 
			
		||||
	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
 | 
			
		||||
	unsigned long old = *p;
 | 
			
		||||
 | 
			
		||||
	*p = old | mask;
 | 
			
		||||
	return (old & mask) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * test_and_clear_bit - Clear a bit and return its old value
 | 
			
		||||
 * @nr: Bit to clear
 | 
			
		||||
 * @addr: Address to count from
 | 
			
		||||
 */
 | 
			
		||||
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mask = BIT_MASK(nr);
 | 
			
		||||
	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
 | 
			
		||||
	unsigned long old = *p;
 | 
			
		||||
 | 
			
		||||
	*p = old & ~mask;
 | 
			
		||||
	return (old & mask) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * test_and_change_bit - Change a bit and return its old value
 | 
			
		||||
 * @nr: Bit to change
 | 
			
		||||
 * @addr: Address to count from
 | 
			
		||||
 */
 | 
			
		||||
static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mask = BIT_MASK(nr);
 | 
			
		||||
	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
 | 
			
		||||
	unsigned long old = *p;
 | 
			
		||||
 | 
			
		||||
	*p = old ^ mask;
 | 
			
		||||
	return (old & mask) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * test_bit - Determine whether a bit is set
 | 
			
		||||
 * @nr: bit number to test
 | 
			
		||||
 * @addr: Address to start counting from
 | 
			
		||||
 */
 | 
			
		||||
static inline int test_bit(int nr, const volatile unsigned long *addr)
 | 
			
		||||
{
 | 
			
		||||
	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * find_last_bit - find the last set bit in a memory region
 | 
			
		||||
 * @addr: The address to start the search at
 | 
			
		||||
 * @size: The maximum size to search
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the bit number of the first set bit, or size.
 | 
			
		||||
 */
 | 
			
		||||
unsigned long find_last_bit(const unsigned long *addr,
 | 
			
		||||
                            unsigned long size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * find_next_bit - find the next set bit in a memory region
 | 
			
		||||
 * @addr: The address to base the search on
 | 
			
		||||
 * @offset: The bitnumber to start searching at
 | 
			
		||||
 * @size: The bitmap size in bits
 | 
			
		||||
 */
 | 
			
		||||
unsigned long find_next_bit(const unsigned long *addr,
 | 
			
		||||
				   unsigned long size, unsigned long offset);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * find_next_zero_bit - find the next cleared bit in a memory region
 | 
			
		||||
 * @addr: The address to base the search on
 | 
			
		||||
 * @offset: The bitnumber to start searching at
 | 
			
		||||
 * @size: The bitmap size in bits
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
unsigned long find_next_zero_bit(const unsigned long *addr,
 | 
			
		||||
                                 unsigned long size,
 | 
			
		||||
                                 unsigned long offset);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * find_first_bit - find the first set bit in a memory region
 | 
			
		||||
 * @addr: The address to start the search at
 | 
			
		||||
 * @size: The maximum size to search
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the bit number of the first set bit.
 | 
			
		||||
 */
 | 
			
		||||
static inline unsigned long find_first_bit(const unsigned long *addr,
 | 
			
		||||
                                           unsigned long size)
 | 
			
		||||
{
 | 
			
		||||
    return find_next_bit(addr, size, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * find_first_zero_bit - find the first cleared bit in a memory region
 | 
			
		||||
 * @addr: The address to start the search at
 | 
			
		||||
 * @size: The maximum size to search
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the bit number of the first cleared bit.
 | 
			
		||||
 */
 | 
			
		||||
static inline unsigned long find_first_zero_bit(const unsigned long *addr,
 | 
			
		||||
                                                unsigned long size)
 | 
			
		||||
{
 | 
			
		||||
    return find_next_zero_bit(addr, size, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned long hweight_long(unsigned long w)
 | 
			
		||||
{
 | 
			
		||||
    unsigned long count;
 | 
			
		||||
 | 
			
		||||
    for (count = 0; w; w >>= 1) {
 | 
			
		||||
        count += w & 1;
 | 
			
		||||
    }
 | 
			
		||||
    return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -9,18 +9,14 @@
 | 
			
		||||
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
			
		||||
 * the COPYING file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributions after 2012-01-13 are licensed under the terms of the
 | 
			
		||||
 * GNU GPL, version 2 or (at your option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "hw/hw.h"
 | 
			
		||||
#include "qemu-queue.h"
 | 
			
		||||
#include "qemu-timer.h"
 | 
			
		||||
#include "monitor.h"
 | 
			
		||||
#include "block-migration.h"
 | 
			
		||||
#include "migration.h"
 | 
			
		||||
#include "blockdev.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
 | 
			
		||||
@@ -30,14 +26,17 @@
 | 
			
		||||
#define BLK_MIG_FLAG_PROGRESS           0x04
 | 
			
		||||
 | 
			
		||||
#define MAX_IS_ALLOCATED_SEARCH 65536
 | 
			
		||||
#define MAX_BLOCKS_READ 10000
 | 
			
		||||
#define BLOCKS_READ_CHANGE 100
 | 
			
		||||
#define INITIAL_BLOCKS_READ 100
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_BLK_MIGRATION
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_BLK_MIGRATION
 | 
			
		||||
#define DPRINTF(fmt, ...) \
 | 
			
		||||
#define dprintf(fmt, ...) \
 | 
			
		||||
    do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0)
 | 
			
		||||
#else
 | 
			
		||||
#define DPRINTF(fmt, ...) \
 | 
			
		||||
#define dprintf(fmt, ...) \
 | 
			
		||||
    do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -46,19 +45,16 @@ typedef struct BlkMigDevState {
 | 
			
		||||
    int bulk_completed;
 | 
			
		||||
    int shared_base;
 | 
			
		||||
    int64_t cur_sector;
 | 
			
		||||
    int64_t cur_dirty;
 | 
			
		||||
    int64_t completed_sectors;
 | 
			
		||||
    int64_t total_sectors;
 | 
			
		||||
    int64_t dirty;
 | 
			
		||||
    QSIMPLEQ_ENTRY(BlkMigDevState) entry;
 | 
			
		||||
    unsigned long *aio_bitmap;
 | 
			
		||||
} BlkMigDevState;
 | 
			
		||||
 | 
			
		||||
typedef struct BlkMigBlock {
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    BlkMigDevState *bmds;
 | 
			
		||||
    int64_t sector;
 | 
			
		||||
    int nr_sectors;
 | 
			
		||||
    struct iovec iov;
 | 
			
		||||
    QEMUIOVector qiov;
 | 
			
		||||
    BlockDriverAIOCB *aiocb;
 | 
			
		||||
@@ -76,10 +72,6 @@ typedef struct BlkMigState {
 | 
			
		||||
    int transferred;
 | 
			
		||||
    int64_t total_sector_sum;
 | 
			
		||||
    int prev_progress;
 | 
			
		||||
    int bulk_completed;
 | 
			
		||||
    long double total_time;
 | 
			
		||||
    long double prev_time_offset;
 | 
			
		||||
    int reads;
 | 
			
		||||
} BlkMigState;
 | 
			
		||||
 | 
			
		||||
static BlkMigState block_mig_state;
 | 
			
		||||
@@ -132,78 +124,21 @@ uint64_t blk_mig_bytes_total(void)
 | 
			
		||||
    return sum << BDRV_SECTOR_BITS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline long double compute_read_bwidth(void)
 | 
			
		||||
{
 | 
			
		||||
    assert(block_mig_state.total_time != 0);
 | 
			
		||||
    return (block_mig_state.reads / block_mig_state.total_time) * BLOCK_SIZE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
 | 
			
		||||
{
 | 
			
		||||
    int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
 | 
			
		||||
 | 
			
		||||
    if ((sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) {
 | 
			
		||||
        return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] &
 | 
			
		||||
            (1UL << (chunk % (sizeof(unsigned long) * 8))));
 | 
			
		||||
    } else {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
 | 
			
		||||
                             int nb_sectors, int set)
 | 
			
		||||
{
 | 
			
		||||
    int64_t start, end;
 | 
			
		||||
    unsigned long val, idx, bit;
 | 
			
		||||
 | 
			
		||||
    start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
 | 
			
		||||
    end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
 | 
			
		||||
 | 
			
		||||
    for (; start <= end; start++) {
 | 
			
		||||
        idx = start / (sizeof(unsigned long) * 8);
 | 
			
		||||
        bit = start % (sizeof(unsigned long) * 8);
 | 
			
		||||
        val = bmds->aio_bitmap[idx];
 | 
			
		||||
        if (set) {
 | 
			
		||||
            val |= 1UL << bit;
 | 
			
		||||
        } else {
 | 
			
		||||
            val &= ~(1UL << bit);
 | 
			
		||||
        }
 | 
			
		||||
        bmds->aio_bitmap[idx] = val;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void alloc_aio_bitmap(BlkMigDevState *bmds)
 | 
			
		||||
{
 | 
			
		||||
    BlockDriverState *bs = bmds->bs;
 | 
			
		||||
    int64_t bitmap_size;
 | 
			
		||||
 | 
			
		||||
    bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
 | 
			
		||||
            BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
 | 
			
		||||
    bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
 | 
			
		||||
 | 
			
		||||
    bmds->aio_bitmap = g_malloc0(bitmap_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blk_mig_read_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    long double curr_time = qemu_get_clock_ns(rt_clock);
 | 
			
		||||
    BlkMigBlock *blk = opaque;
 | 
			
		||||
 | 
			
		||||
    blk->ret = ret;
 | 
			
		||||
 | 
			
		||||
    block_mig_state.reads++;
 | 
			
		||||
    block_mig_state.total_time += (curr_time - block_mig_state.prev_time_offset);
 | 
			
		||||
    block_mig_state.prev_time_offset = curr_time;
 | 
			
		||||
 | 
			
		||||
    QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
 | 
			
		||||
    bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
 | 
			
		||||
 | 
			
		||||
    block_mig_state.submitted--;
 | 
			
		||||
    block_mig_state.read_done++;
 | 
			
		||||
    assert(block_mig_state.submitted >= 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
 | 
			
		||||
static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
 | 
			
		||||
                                BlkMigDevState *bmds, int is_async)
 | 
			
		||||
{
 | 
			
		||||
    int64_t total_sectors = bmds->total_sectors;
 | 
			
		||||
    int64_t cur_sector = bmds->cur_sector;
 | 
			
		||||
@@ -235,28 +170,43 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
 | 
			
		||||
        nr_sectors = total_sectors - cur_sector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    blk = g_malloc(sizeof(BlkMigBlock));
 | 
			
		||||
    blk->buf = g_malloc(BLOCK_SIZE);
 | 
			
		||||
    blk = qemu_malloc(sizeof(BlkMigBlock));
 | 
			
		||||
    blk->buf = qemu_malloc(BLOCK_SIZE);
 | 
			
		||||
    blk->bmds = bmds;
 | 
			
		||||
    blk->sector = cur_sector;
 | 
			
		||||
    blk->nr_sectors = nr_sectors;
 | 
			
		||||
 | 
			
		||||
    if (is_async) {
 | 
			
		||||
        blk->iov.iov_base = blk->buf;
 | 
			
		||||
        blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
 | 
			
		||||
        qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
 | 
			
		||||
 | 
			
		||||
    if (block_mig_state.submitted == 0) {
 | 
			
		||||
        block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
 | 
			
		||||
                                    nr_sectors, blk_mig_read_cb, blk);
 | 
			
		||||
        if (!blk->aiocb) {
 | 
			
		||||
            goto error;
 | 
			
		||||
        }
 | 
			
		||||
        block_mig_state.submitted++;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (bdrv_read(bs, cur_sector, blk->buf, nr_sectors) < 0) {
 | 
			
		||||
            goto error;
 | 
			
		||||
        }
 | 
			
		||||
        blk_send(f, blk);
 | 
			
		||||
 | 
			
		||||
        qemu_free(blk->buf);
 | 
			
		||||
        qemu_free(blk);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bdrv_reset_dirty(bs, cur_sector, nr_sectors);
 | 
			
		||||
    bmds->cur_sector = cur_sector + nr_sectors;
 | 
			
		||||
 | 
			
		||||
    return (bmds->cur_sector >= total_sectors);
 | 
			
		||||
 | 
			
		||||
error:
 | 
			
		||||
    monitor_printf(mon, "Error reading sector %" PRId64 "\n", cur_sector);
 | 
			
		||||
    qemu_file_set_error(f);
 | 
			
		||||
    qemu_free(blk->buf);
 | 
			
		||||
    qemu_free(blk);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_dirty_tracking(int enable)
 | 
			
		||||
@@ -268,55 +218,49 @@ static void set_dirty_tracking(int enable)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
 | 
			
		||||
static void init_blk_migration(Monitor *mon, QEMUFile *f)
 | 
			
		||||
{
 | 
			
		||||
    BlkMigDevState *bmds;
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
    int64_t sectors;
 | 
			
		||||
 | 
			
		||||
    if (!bdrv_is_read_only(bs)) {
 | 
			
		||||
        sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
 | 
			
		||||
        if (sectors <= 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bmds = g_malloc0(sizeof(BlkMigDevState));
 | 
			
		||||
        bmds->bs = bs;
 | 
			
		||||
        bmds->bulk_completed = 0;
 | 
			
		||||
        bmds->total_sectors = sectors;
 | 
			
		||||
        bmds->completed_sectors = 0;
 | 
			
		||||
        bmds->shared_base = block_mig_state.shared_base;
 | 
			
		||||
        alloc_aio_bitmap(bmds);
 | 
			
		||||
        drive_get_ref(drive_get_by_blockdev(bs));
 | 
			
		||||
        bdrv_set_in_use(bs, 1);
 | 
			
		||||
 | 
			
		||||
        block_mig_state.total_sector_sum += sectors;
 | 
			
		||||
 | 
			
		||||
        if (bmds->shared_base) {
 | 
			
		||||
            DPRINTF("Start migration for %s with shared base image\n",
 | 
			
		||||
                    bs->device_name);
 | 
			
		||||
        } else {
 | 
			
		||||
            DPRINTF("Start full migration for %s\n", bs->device_name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void init_blk_migration(QEMUFile *f)
 | 
			
		||||
{
 | 
			
		||||
    block_mig_state.submitted = 0;
 | 
			
		||||
    block_mig_state.read_done = 0;
 | 
			
		||||
    block_mig_state.transferred = 0;
 | 
			
		||||
    block_mig_state.total_sector_sum = 0;
 | 
			
		||||
    block_mig_state.prev_progress = -1;
 | 
			
		||||
    block_mig_state.bulk_completed = 0;
 | 
			
		||||
    block_mig_state.total_time = 0;
 | 
			
		||||
    block_mig_state.reads = 0;
 | 
			
		||||
 | 
			
		||||
    bdrv_iterate(init_blk_migration_it, NULL);
 | 
			
		||||
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
 | 
			
		||||
        if (bs->type == BDRV_TYPE_HD) {
 | 
			
		||||
            sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
 | 
			
		||||
            if (sectors == 0) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bmds = qemu_mallocz(sizeof(BlkMigDevState));
 | 
			
		||||
            bmds->bs = bs;
 | 
			
		||||
            bmds->bulk_completed = 0;
 | 
			
		||||
            bmds->total_sectors = sectors;
 | 
			
		||||
            bmds->completed_sectors = 0;
 | 
			
		||||
            bmds->shared_base = block_mig_state.shared_base;
 | 
			
		||||
 | 
			
		||||
            block_mig_state.total_sector_sum += sectors;
 | 
			
		||||
 | 
			
		||||
            if (bmds->shared_base) {
 | 
			
		||||
                monitor_printf(mon, "Start migration for %s with shared base "
 | 
			
		||||
                                    "image\n",
 | 
			
		||||
                               bs->device_name);
 | 
			
		||||
            } else {
 | 
			
		||||
                monitor_printf(mon, "Start full migration for %s\n",
 | 
			
		||||
                               bs->device_name);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int blk_mig_save_bulked_block(QEMUFile *f)
 | 
			
		||||
static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async)
 | 
			
		||||
{
 | 
			
		||||
    int64_t completed_sector_sum = 0;
 | 
			
		||||
    BlkMigDevState *bmds;
 | 
			
		||||
@@ -325,7 +269,7 @@ static int blk_mig_save_bulked_block(QEMUFile *f)
 | 
			
		||||
 | 
			
		||||
    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
			
		||||
        if (bmds->bulk_completed == 0) {
 | 
			
		||||
            if (mig_save_device_bulk(f, bmds) == 1) {
 | 
			
		||||
            if (mig_save_device_bulk(mon, f, bmds, is_async) == 1) {
 | 
			
		||||
                /* completed bulk section for this device */
 | 
			
		||||
                bmds->bulk_completed = 1;
 | 
			
		||||
            }
 | 
			
		||||
@@ -337,118 +281,58 @@ static int blk_mig_save_bulked_block(QEMUFile *f)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (block_mig_state.total_sector_sum != 0) {
 | 
			
		||||
        progress = completed_sector_sum * 100 /
 | 
			
		||||
                   block_mig_state.total_sector_sum;
 | 
			
		||||
    } else {
 | 
			
		||||
        progress = 100;
 | 
			
		||||
    }
 | 
			
		||||
    progress = completed_sector_sum * 100 / block_mig_state.total_sector_sum;
 | 
			
		||||
    if (progress != block_mig_state.prev_progress) {
 | 
			
		||||
        block_mig_state.prev_progress = progress;
 | 
			
		||||
        qemu_put_be64(f, (progress << BDRV_SECTOR_BITS)
 | 
			
		||||
                         | BLK_MIG_FLAG_PROGRESS);
 | 
			
		||||
        DPRINTF("Completed %d %%\r", progress);
 | 
			
		||||
        monitor_printf(mon, "Completed %d %%\r", progress);
 | 
			
		||||
        monitor_flush(mon);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blk_mig_reset_dirty_cursor(void)
 | 
			
		||||
#define MAX_NUM_BLOCKS 4
 | 
			
		||||
 | 
			
		||||
static void blk_mig_save_dirty_blocks(Monitor *mon, QEMUFile *f)
 | 
			
		||||
{
 | 
			
		||||
    BlkMigDevState *bmds;
 | 
			
		||||
    BlkMigBlock blk;
 | 
			
		||||
    int64_t sector;
 | 
			
		||||
 | 
			
		||||
    blk.buf = qemu_malloc(BLOCK_SIZE);
 | 
			
		||||
 | 
			
		||||
    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
			
		||||
        bmds->cur_dirty = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
 | 
			
		||||
                                 int is_async)
 | 
			
		||||
{
 | 
			
		||||
    BlkMigBlock *blk;
 | 
			
		||||
    int64_t total_sectors = bmds->total_sectors;
 | 
			
		||||
    int64_t sector;
 | 
			
		||||
    int nr_sectors;
 | 
			
		||||
    int ret = -EIO;
 | 
			
		||||
 | 
			
		||||
    for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
 | 
			
		||||
        if (bmds_aio_inflight(bmds, sector)) {
 | 
			
		||||
            bdrv_drain_all();
 | 
			
		||||
        }
 | 
			
		||||
        for (sector = 0; sector < bmds->cur_sector;) {
 | 
			
		||||
            if (bdrv_get_dirty(bmds->bs, sector)) {
 | 
			
		||||
 | 
			
		||||
            if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
 | 
			
		||||
                nr_sectors = total_sectors - sector;
 | 
			
		||||
            } else {
 | 
			
		||||
                nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
 | 
			
		||||
                if (bdrv_read(bmds->bs, sector, blk.buf,
 | 
			
		||||
                              BDRV_SECTORS_PER_DIRTY_CHUNK) < 0) {
 | 
			
		||||
                    monitor_printf(mon, "Error reading sector %" PRId64 "\n",
 | 
			
		||||
                                   sector);
 | 
			
		||||
                    qemu_file_set_error(f);
 | 
			
		||||
                    qemu_free(blk.buf);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            blk = g_malloc(sizeof(BlkMigBlock));
 | 
			
		||||
            blk->buf = g_malloc(BLOCK_SIZE);
 | 
			
		||||
            blk->bmds = bmds;
 | 
			
		||||
            blk->sector = sector;
 | 
			
		||||
            blk->nr_sectors = nr_sectors;
 | 
			
		||||
                blk.bmds = bmds;
 | 
			
		||||
                blk.sector = sector;
 | 
			
		||||
                blk_send(f, &blk);
 | 
			
		||||
 | 
			
		||||
            if (is_async) {
 | 
			
		||||
                blk->iov.iov_base = blk->buf;
 | 
			
		||||
                blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
 | 
			
		||||
                qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
 | 
			
		||||
 | 
			
		||||
                if (block_mig_state.submitted == 0) {
 | 
			
		||||
                    block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
 | 
			
		||||
                                            nr_sectors, blk_mig_read_cb, blk);
 | 
			
		||||
                block_mig_state.submitted++;
 | 
			
		||||
                bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
 | 
			
		||||
            } else {
 | 
			
		||||
                ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors);
 | 
			
		||||
                if (ret < 0) {
 | 
			
		||||
                    goto error;
 | 
			
		||||
                }
 | 
			
		||||
                blk_send(f, blk);
 | 
			
		||||
 | 
			
		||||
                g_free(blk->buf);
 | 
			
		||||
                g_free(blk);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bdrv_reset_dirty(bmds->bs, sector, nr_sectors);
 | 
			
		||||
            break;
 | 
			
		||||
                bdrv_reset_dirty(bmds->bs, sector,
 | 
			
		||||
                                 BDRV_SECTORS_PER_DIRTY_CHUNK);
 | 
			
		||||
            }
 | 
			
		||||
            sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
 | 
			
		||||
        bmds->cur_dirty = sector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (bmds->cur_dirty >= bmds->total_sectors);
 | 
			
		||||
 | 
			
		||||
error:
 | 
			
		||||
    DPRINTF("Error reading sector %" PRId64 "\n", sector);
 | 
			
		||||
    qemu_file_set_error(f, ret);
 | 
			
		||||
    g_free(blk->buf);
 | 
			
		||||
    g_free(blk);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int blk_mig_save_dirty_block(QEMUFile *f, int is_async)
 | 
			
		||||
{
 | 
			
		||||
    BlkMigDevState *bmds;
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
 | 
			
		||||
    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
			
		||||
        if (mig_save_device_dirty(f, bmds, is_async) == 0) {
 | 
			
		||||
            ret = 1;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
    qemu_free(blk.buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void flush_blks(QEMUFile* f)
 | 
			
		||||
{
 | 
			
		||||
    BlkMigBlock *blk;
 | 
			
		||||
 | 
			
		||||
    DPRINTF("%s Enter submitted %d read_done %d transferred %d\n",
 | 
			
		||||
    dprintf("%s Enter submitted %d read_done %d transferred %d\n",
 | 
			
		||||
            __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
 | 
			
		||||
            block_mig_state.transferred);
 | 
			
		||||
 | 
			
		||||
@@ -457,94 +341,70 @@ static void flush_blks(QEMUFile* f)
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (blk->ret < 0) {
 | 
			
		||||
            qemu_file_set_error(f, blk->ret);
 | 
			
		||||
            qemu_file_set_error(f);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        blk_send(f, blk);
 | 
			
		||||
 | 
			
		||||
        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
 | 
			
		||||
        g_free(blk->buf);
 | 
			
		||||
        g_free(blk);
 | 
			
		||||
        qemu_free(blk->buf);
 | 
			
		||||
        qemu_free(blk);
 | 
			
		||||
 | 
			
		||||
        block_mig_state.read_done--;
 | 
			
		||||
        block_mig_state.transferred++;
 | 
			
		||||
        assert(block_mig_state.read_done >= 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
 | 
			
		||||
    dprintf("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
 | 
			
		||||
            block_mig_state.submitted, block_mig_state.read_done,
 | 
			
		||||
            block_mig_state.transferred);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t get_remaining_dirty(void)
 | 
			
		||||
{
 | 
			
		||||
    BlkMigDevState *bmds;
 | 
			
		||||
    int64_t dirty = 0;
 | 
			
		||||
 | 
			
		||||
    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
			
		||||
        dirty += bdrv_get_dirty_count(bmds->bs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return dirty * BLOCK_SIZE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int is_stage2_completed(void)
 | 
			
		||||
{
 | 
			
		||||
    int64_t remaining_dirty;
 | 
			
		||||
    long double bwidth;
 | 
			
		||||
 | 
			
		||||
    if (block_mig_state.bulk_completed == 1) {
 | 
			
		||||
 | 
			
		||||
        remaining_dirty = get_remaining_dirty();
 | 
			
		||||
        if (remaining_dirty == 0) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bwidth = compute_read_bwidth();
 | 
			
		||||
 | 
			
		||||
        if ((remaining_dirty / bwidth) <=
 | 
			
		||||
            migrate_max_downtime()) {
 | 
			
		||||
            /* finish stage2 because we think that we can finish remaining work
 | 
			
		||||
               below max_downtime */
 | 
			
		||||
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    BlkMigDevState *bmds;
 | 
			
		||||
 | 
			
		||||
    if (block_mig_state.submitted > 0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
			
		||||
        if (bmds->bulk_completed == 0) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blk_mig_cleanup(void)
 | 
			
		||||
static void blk_mig_cleanup(Monitor *mon)
 | 
			
		||||
{
 | 
			
		||||
    BlkMigDevState *bmds;
 | 
			
		||||
    BlkMigBlock *blk;
 | 
			
		||||
 | 
			
		||||
    set_dirty_tracking(0);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        drive_put_ref(drive_get_by_blockdev(bmds->bs));
 | 
			
		||||
        g_free(bmds->aio_bitmap);
 | 
			
		||||
        g_free(bmds);
 | 
			
		||||
        qemu_free(bmds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
 | 
			
		||||
        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
 | 
			
		||||
        g_free(blk->buf);
 | 
			
		||||
        g_free(blk);
 | 
			
		||||
        qemu_free(blk->buf);
 | 
			
		||||
        qemu_free(blk);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set_dirty_tracking(0);
 | 
			
		||||
 | 
			
		||||
    monitor_printf(mon, "\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int block_save_live(QEMUFile *f, int stage, void *opaque)
 | 
			
		||||
static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    DPRINTF("Enter save live stage %d submitted %d transferred %d\n",
 | 
			
		||||
    dprintf("Enter save live stage %d submitted %d transferred %d\n",
 | 
			
		||||
            stage, block_mig_state.submitted, block_mig_state.transferred);
 | 
			
		||||
 | 
			
		||||
    if (stage < 0) {
 | 
			
		||||
        blk_mig_cleanup();
 | 
			
		||||
        blk_mig_cleanup(mon);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -555,7 +415,7 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (stage == 1) {
 | 
			
		||||
        init_blk_migration(f);
 | 
			
		||||
        init_blk_migration(mon, f);
 | 
			
		||||
 | 
			
		||||
        /* start track dirty blocks */
 | 
			
		||||
        set_dirty_tracking(1);
 | 
			
		||||
@@ -563,59 +423,44 @@ static int block_save_live(QEMUFile *f, int stage, void *opaque)
 | 
			
		||||
 | 
			
		||||
    flush_blks(f);
 | 
			
		||||
 | 
			
		||||
    ret = qemu_file_get_error(f);
 | 
			
		||||
    if (ret) {
 | 
			
		||||
        blk_mig_cleanup();
 | 
			
		||||
        return ret;
 | 
			
		||||
    if (qemu_file_has_error(f)) {
 | 
			
		||||
        blk_mig_cleanup(mon);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    blk_mig_reset_dirty_cursor();
 | 
			
		||||
 | 
			
		||||
    if (stage == 2) {
 | 
			
		||||
    /* control the rate of transfer */
 | 
			
		||||
    while ((block_mig_state.submitted +
 | 
			
		||||
            block_mig_state.read_done) * BLOCK_SIZE <
 | 
			
		||||
           qemu_file_get_rate_limit(f)) {
 | 
			
		||||
            if (block_mig_state.bulk_completed == 0) {
 | 
			
		||||
                /* first finish the bulk phase */
 | 
			
		||||
                if (blk_mig_save_bulked_block(f) == 0) {
 | 
			
		||||
                    /* finished saving bulk on all devices */
 | 
			
		||||
                    block_mig_state.bulk_completed = 1;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if (blk_mig_save_dirty_block(f, 1) == 0) {
 | 
			
		||||
                    /* no more dirty blocks */
 | 
			
		||||
        if (blk_mig_save_bulked_block(mon, f, 1) == 0) {
 | 
			
		||||
            /* no more bulk blocks for now */
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    flush_blks(f);
 | 
			
		||||
 | 
			
		||||
        ret = qemu_file_get_error(f);
 | 
			
		||||
        if (ret) {
 | 
			
		||||
            blk_mig_cleanup();
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
    if (qemu_file_has_error(f)) {
 | 
			
		||||
        blk_mig_cleanup(mon);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (stage == 3) {
 | 
			
		||||
        /* we know for sure that save bulk is completed and
 | 
			
		||||
           all async read completed */
 | 
			
		||||
        assert(block_mig_state.submitted == 0);
 | 
			
		||||
        while (blk_mig_save_bulked_block(mon, f, 0) != 0) {
 | 
			
		||||
            /* empty */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while (blk_mig_save_dirty_block(f, 0) != 0);
 | 
			
		||||
        blk_mig_cleanup();
 | 
			
		||||
        blk_mig_save_dirty_blocks(mon, f);
 | 
			
		||||
        blk_mig_cleanup(mon);
 | 
			
		||||
 | 
			
		||||
        /* report completion */
 | 
			
		||||
        qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
 | 
			
		||||
 | 
			
		||||
        ret = qemu_file_get_error(f);
 | 
			
		||||
        if (ret) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        if (qemu_file_has_error(f)) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DPRINTF("Block migration completed\n");
 | 
			
		||||
        monitor_printf(mon, "Block migration completed\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_put_be64(f, BLK_MIG_FLAG_EOS);
 | 
			
		||||
@@ -629,11 +474,8 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
 | 
			
		||||
    int len, flags;
 | 
			
		||||
    char device_name[256];
 | 
			
		||||
    int64_t addr;
 | 
			
		||||
    BlockDriverState *bs, *bs_prev = NULL;
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    int64_t total_sectors = 0;
 | 
			
		||||
    int nr_sectors;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        addr = qemu_get_be64(f);
 | 
			
		||||
@@ -654,31 +496,12 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
 | 
			
		||||
                return -EINVAL;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (bs != bs_prev) {
 | 
			
		||||
                bs_prev = bs;
 | 
			
		||||
                total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
 | 
			
		||||
                if (total_sectors <= 0) {
 | 
			
		||||
                    error_report("Error getting length of block device %s",
 | 
			
		||||
                                 device_name);
 | 
			
		||||
                    return -EINVAL;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (total_sectors - addr < BDRV_SECTORS_PER_DIRTY_CHUNK) {
 | 
			
		||||
                nr_sectors = total_sectors - addr;
 | 
			
		||||
            } else {
 | 
			
		||||
                nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            buf = g_malloc(BLOCK_SIZE);
 | 
			
		||||
            buf = qemu_malloc(BLOCK_SIZE);
 | 
			
		||||
 | 
			
		||||
            qemu_get_buffer(f, buf, BLOCK_SIZE);
 | 
			
		||||
            ret = bdrv_write(bs, addr, buf, nr_sectors);
 | 
			
		||||
            bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK);
 | 
			
		||||
 | 
			
		||||
            g_free(buf);
 | 
			
		||||
            if (ret < 0) {
 | 
			
		||||
                return ret;
 | 
			
		||||
            }
 | 
			
		||||
            qemu_free(buf);
 | 
			
		||||
        } else if (flags & BLK_MIG_FLAG_PROGRESS) {
 | 
			
		||||
            if (!banner_printed) {
 | 
			
		||||
                printf("Receiving block device images\n");
 | 
			
		||||
@@ -691,9 +514,8 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
 | 
			
		||||
            fprintf(stderr, "Unknown flags\n");
 | 
			
		||||
            return -EINVAL;
 | 
			
		||||
        }
 | 
			
		||||
        ret = qemu_file_get_error(f);
 | 
			
		||||
        if (ret != 0) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        if (qemu_file_has_error(f)) {
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        }
 | 
			
		||||
    } while (!(flags & BLK_MIG_FLAG_EOS));
 | 
			
		||||
 | 
			
		||||
@@ -714,6 +536,6 @@ void blk_mig_init(void)
 | 
			
		||||
    QSIMPLEQ_INIT(&block_mig_state.bmds_list);
 | 
			
		||||
    QSIMPLEQ_INIT(&block_mig_state.blk_list);
 | 
			
		||||
 | 
			
		||||
    register_savevm_live(NULL, "block", 0, 1, block_set_params,
 | 
			
		||||
                         block_save_live, NULL, block_load, &block_mig_state);
 | 
			
		||||
    register_savevm_live("block", 0, 1, block_set_params, block_save_live,
 | 
			
		||||
                         NULL, block_load, &block_mig_state);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										324
									
								
								block.h
									
									
									
									
									
								
							
							
						
						
									
										324
									
								
								block.h
									
									
									
									
									
								
							@@ -4,7 +4,6 @@
 | 
			
		||||
#include "qemu-aio.h"
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "qemu-option.h"
 | 
			
		||||
#include "qemu-coroutine.h"
 | 
			
		||||
#include "qobject.h"
 | 
			
		||||
 | 
			
		||||
/* block.c */
 | 
			
		||||
@@ -15,130 +14,61 @@ typedef struct BlockDriverInfo {
 | 
			
		||||
    int cluster_size;
 | 
			
		||||
    /* offset at which the VM state can be saved (0 if not possible) */
 | 
			
		||||
    int64_t vm_state_offset;
 | 
			
		||||
    bool is_dirty;
 | 
			
		||||
} BlockDriverInfo;
 | 
			
		||||
 | 
			
		||||
typedef struct BlockFragInfo {
 | 
			
		||||
    uint64_t allocated_clusters;
 | 
			
		||||
    uint64_t total_clusters;
 | 
			
		||||
    uint64_t fragmented_clusters;
 | 
			
		||||
} BlockFragInfo;
 | 
			
		||||
 | 
			
		||||
typedef struct QEMUSnapshotInfo {
 | 
			
		||||
    char id_str[128]; /* unique snapshot id */
 | 
			
		||||
    /* the following fields are informative. They are not needed for
 | 
			
		||||
       the consistency of the snapshot */
 | 
			
		||||
    char name[256]; /* user chosen name */
 | 
			
		||||
    uint64_t vm_state_size; /* VM state info size */
 | 
			
		||||
    char name[256]; /* user choosen name */
 | 
			
		||||
    uint32_t vm_state_size; /* VM state info size */
 | 
			
		||||
    uint32_t date_sec; /* UTC date of the snapshot */
 | 
			
		||||
    uint32_t date_nsec;
 | 
			
		||||
    uint64_t vm_clock_nsec; /* VM clock relative to boot */
 | 
			
		||||
} QEMUSnapshotInfo;
 | 
			
		||||
 | 
			
		||||
/* Callbacks for block device models */
 | 
			
		||||
typedef struct BlockDevOps {
 | 
			
		||||
    /*
 | 
			
		||||
     * Runs when virtual media changed (monitor commands eject, change)
 | 
			
		||||
     * Argument load is true on load and false on eject.
 | 
			
		||||
     * Beware: doesn't run when a host device's physical media
 | 
			
		||||
     * changes.  Sure would be useful if it did.
 | 
			
		||||
     * Device models with removable media must implement this callback.
 | 
			
		||||
     */
 | 
			
		||||
    void (*change_media_cb)(void *opaque, bool load);
 | 
			
		||||
    /*
 | 
			
		||||
     * Runs when an eject request is issued from the monitor, the tray
 | 
			
		||||
     * is closed, and the medium is locked.
 | 
			
		||||
     * Device models that do not implement is_medium_locked will not need
 | 
			
		||||
     * this callback.  Device models that can lock the medium or tray might
 | 
			
		||||
     * want to implement the callback and unlock the tray when "force" is
 | 
			
		||||
     * true, even if they do not support eject requests.
 | 
			
		||||
     */
 | 
			
		||||
    void (*eject_request_cb)(void *opaque, bool force);
 | 
			
		||||
    /*
 | 
			
		||||
     * Is the virtual tray open?
 | 
			
		||||
     * Device models implement this only when the device has a tray.
 | 
			
		||||
     */
 | 
			
		||||
    bool (*is_tray_open)(void *opaque);
 | 
			
		||||
    /*
 | 
			
		||||
     * Is the virtual medium locked into the device?
 | 
			
		||||
     * Device models implement this only when device has such a lock.
 | 
			
		||||
     */
 | 
			
		||||
    bool (*is_medium_locked)(void *opaque);
 | 
			
		||||
    /*
 | 
			
		||||
     * Runs when the size changed (e.g. monitor command block_resize)
 | 
			
		||||
     */
 | 
			
		||||
    void (*resize_cb)(void *opaque);
 | 
			
		||||
} BlockDevOps;
 | 
			
		||||
 | 
			
		||||
#define BDRV_O_RDONLY      0x0000
 | 
			
		||||
#define BDRV_O_RDWR        0x0002
 | 
			
		||||
#define BDRV_O_ACCESS      0x0003
 | 
			
		||||
#define BDRV_O_CREAT       0x0004 /* create an empty file */
 | 
			
		||||
#define BDRV_O_SNAPSHOT    0x0008 /* open the file read only and save writes in a snapshot */
 | 
			
		||||
#define BDRV_O_FILE        0x0010 /* open as a raw file (do not try to
 | 
			
		||||
                                     use a disk image format on top of
 | 
			
		||||
                                     it (default for
 | 
			
		||||
                                     bdrv_file_open()) */
 | 
			
		||||
#define BDRV_O_NOCACHE     0x0020 /* do not use the host page cache */
 | 
			
		||||
#define BDRV_O_CACHE_WB    0x0040 /* use write-back caching */
 | 
			
		||||
#define BDRV_O_NATIVE_AIO  0x0080 /* use native AIO instead of the thread pool */
 | 
			
		||||
#define BDRV_O_NO_BACKING  0x0100 /* don't open the backing file */
 | 
			
		||||
#define BDRV_O_NO_FLUSH    0x0200 /* disable flushing on this disk */
 | 
			
		||||
#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */
 | 
			
		||||
#define BDRV_O_INCOMING    0x0800  /* consistency hint for incoming migration */
 | 
			
		||||
 | 
			
		||||
#define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
 | 
			
		||||
#define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_CACHE_WB)
 | 
			
		||||
 | 
			
		||||
#define BDRV_SECTOR_BITS   9
 | 
			
		||||
#define BDRV_SECTOR_SIZE   (1ULL << BDRV_SECTOR_BITS)
 | 
			
		||||
#define BDRV_SECTOR_MASK   ~(BDRV_SECTOR_SIZE - 1)
 | 
			
		||||
#define BDRV_SECTOR_SIZE   (1 << BDRV_SECTOR_BITS)
 | 
			
		||||
#define BDRV_SECTOR_MASK   ~(BDRV_SECTOR_SIZE - 1);
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC,
 | 
			
		||||
    BLOCK_ERR_STOP_ANY
 | 
			
		||||
} BlockErrorAction;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
 | 
			
		||||
} BlockQMPEventAction;
 | 
			
		||||
 | 
			
		||||
void bdrv_iostatus_enable(BlockDriverState *bs);
 | 
			
		||||
void bdrv_iostatus_reset(BlockDriverState *bs);
 | 
			
		||||
void bdrv_iostatus_disable(BlockDriverState *bs);
 | 
			
		||||
bool bdrv_iostatus_is_enabled(const BlockDriverState *bs);
 | 
			
		||||
void bdrv_iostatus_set_err(BlockDriverState *bs, int error);
 | 
			
		||||
void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
 | 
			
		||||
                               BlockQMPEventAction action, int is_read);
 | 
			
		||||
void bdrv_info_print(Monitor *mon, const QObject *data);
 | 
			
		||||
void bdrv_info(Monitor *mon, QObject **ret_data);
 | 
			
		||||
void bdrv_stats_print(Monitor *mon, const QObject *data);
 | 
			
		||||
void bdrv_info_stats(Monitor *mon, QObject **ret_data);
 | 
			
		||||
 | 
			
		||||
/* disk I/O throttling */
 | 
			
		||||
void bdrv_io_limits_enable(BlockDriverState *bs);
 | 
			
		||||
void bdrv_io_limits_disable(BlockDriverState *bs);
 | 
			
		||||
bool bdrv_io_limits_enabled(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
void bdrv_init(void);
 | 
			
		||||
void bdrv_init_with_whitelist(void);
 | 
			
		||||
BlockDriver *bdrv_find_protocol(const char *filename);
 | 
			
		||||
BlockDriver *bdrv_find_format(const char *format_name);
 | 
			
		||||
BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
 | 
			
		||||
int bdrv_create(BlockDriver *drv, const char* filename,
 | 
			
		||||
    QEMUOptionParameter *options);
 | 
			
		||||
int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
 | 
			
		||||
int bdrv_create2(BlockDriver *drv,
 | 
			
		||||
                 const char *filename, int64_t size_in_sectors,
 | 
			
		||||
                 const char *backing_file, const char *backing_format,
 | 
			
		||||
                 int flags);
 | 
			
		||||
BlockDriverState *bdrv_new(const char *device_name);
 | 
			
		||||
void bdrv_make_anon(BlockDriverState *bs);
 | 
			
		||||
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
 | 
			
		||||
void bdrv_delete(BlockDriverState *bs);
 | 
			
		||||
int bdrv_parse_cache_flags(const char *mode, int *flags);
 | 
			
		||||
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
 | 
			
		||||
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
 | 
			
		||||
int bdrv_open(BlockDriverState *bs, const char *filename, int flags);
 | 
			
		||||
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
 | 
			
		||||
               BlockDriver *drv);
 | 
			
		||||
void bdrv_close(BlockDriverState *bs);
 | 
			
		||||
int bdrv_attach_dev(BlockDriverState *bs, void *dev);
 | 
			
		||||
void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
 | 
			
		||||
void bdrv_detach_dev(BlockDriverState *bs, void *dev);
 | 
			
		||||
void *bdrv_get_attached_dev(BlockDriverState *bs);
 | 
			
		||||
void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
 | 
			
		||||
                      void *opaque);
 | 
			
		||||
void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
 | 
			
		||||
bool bdrv_dev_has_removable_media(BlockDriverState *bs);
 | 
			
		||||
bool bdrv_dev_is_tray_open(BlockDriverState *bs);
 | 
			
		||||
bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
 | 
			
		||||
int bdrv_check(BlockDriverState *bs);
 | 
			
		||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
              uint8_t *buf, int nb_sectors);
 | 
			
		||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
@@ -149,46 +79,18 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
                const void *buf, int count);
 | 
			
		||||
int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
 | 
			
		||||
    const void *buf, int count);
 | 
			
		||||
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    int nb_sectors, QEMUIOVector *qiov);
 | 
			
		||||
int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
 | 
			
		||||
    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
 | 
			
		||||
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    int nb_sectors, QEMUIOVector *qiov);
 | 
			
		||||
/*
 | 
			
		||||
 * Efficiently zero a region of the disk image.  Note that this is a regular
 | 
			
		||||
 * I/O request like read or write and should have a reasonable size.  This
 | 
			
		||||
 * function is not suitable for zeroing the entire image in a single request
 | 
			
		||||
 * because it may allocate memory for the entire region.
 | 
			
		||||
 */
 | 
			
		||||
int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    int nb_sectors);
 | 
			
		||||
int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    int nb_sectors, int *pnum);
 | 
			
		||||
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
 | 
			
		||||
    const char *backing_file);
 | 
			
		||||
int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    const uint8_t *buf, int nb_sectors);
 | 
			
		||||
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 | 
			
		||||
int64_t bdrv_getlength(BlockDriverState *bs);
 | 
			
		||||
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
 | 
			
		||||
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
 | 
			
		||||
void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
 | 
			
		||||
int bdrv_commit(BlockDriverState *bs);
 | 
			
		||||
int bdrv_commit_all(void);
 | 
			
		||||
int bdrv_change_backing_file(BlockDriverState *bs,
 | 
			
		||||
    const char *backing_file, const char *backing_fmt);
 | 
			
		||||
void bdrv_register(BlockDriver *bdrv);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct BdrvCheckResult {
 | 
			
		||||
    int corruptions;
 | 
			
		||||
    int leaks;
 | 
			
		||||
    int check_errors;
 | 
			
		||||
    BlockFragInfo bfi;
 | 
			
		||||
} BdrvCheckResult;
 | 
			
		||||
 | 
			
		||||
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res);
 | 
			
		||||
 | 
			
		||||
/* async block I/O */
 | 
			
		||||
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
 | 
			
		||||
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
 | 
			
		||||
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
 | 
			
		||||
				     int sector_num);
 | 
			
		||||
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
@@ -199,9 +101,6 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                  BlockDriverCompletionFunc *cb, void *opaque);
 | 
			
		||||
BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
 | 
			
		||||
				 BlockDriverCompletionFunc *cb, void *opaque);
 | 
			
		||||
BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
 | 
			
		||||
                                   int64_t sector_num, int nb_sectors,
 | 
			
		||||
                                   BlockDriverCompletionFunc *cb, void *opaque);
 | 
			
		||||
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
 | 
			
		||||
 | 
			
		||||
typedef struct BlockRequest {
 | 
			
		||||
@@ -225,25 +124,16 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
 | 
			
		||||
        unsigned long int req, void *buf,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque);
 | 
			
		||||
 | 
			
		||||
/* Invalidate any cached metadata used by image formats */
 | 
			
		||||
void bdrv_invalidate_cache(BlockDriverState *bs);
 | 
			
		||||
void bdrv_invalidate_cache_all(void);
 | 
			
		||||
 | 
			
		||||
void bdrv_clear_incoming_migration_all(void);
 | 
			
		||||
 | 
			
		||||
/* Ensure contents are flushed to disk.  */
 | 
			
		||||
int bdrv_flush(BlockDriverState *bs);
 | 
			
		||||
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
 | 
			
		||||
void bdrv_flush(BlockDriverState *bs);
 | 
			
		||||
void bdrv_flush_all(void);
 | 
			
		||||
void bdrv_close_all(void);
 | 
			
		||||
void bdrv_drain_all(void);
 | 
			
		||||
 | 
			
		||||
int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
 | 
			
		||||
int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
 | 
			
		||||
int bdrv_has_zero_init(BlockDriverState *bs);
 | 
			
		||||
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
 | 
			
		||||
	int *pnum);
 | 
			
		||||
 | 
			
		||||
#define BDRV_TYPE_HD     0
 | 
			
		||||
#define BDRV_TYPE_CDROM  1
 | 
			
		||||
#define BDRV_TYPE_FLOPPY 2
 | 
			
		||||
#define BIOS_ATA_TRANSLATION_AUTO   0
 | 
			
		||||
#define BIOS_ATA_TRANSLATION_NONE   1
 | 
			
		||||
#define BIOS_ATA_TRANSLATION_LBA    2
 | 
			
		||||
@@ -252,41 +142,26 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
 | 
			
		||||
 | 
			
		||||
void bdrv_set_geometry_hint(BlockDriverState *bs,
 | 
			
		||||
                            int cyls, int heads, int secs);
 | 
			
		||||
void bdrv_set_type_hint(BlockDriverState *bs, int type);
 | 
			
		||||
void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
 | 
			
		||||
void bdrv_get_geometry_hint(BlockDriverState *bs,
 | 
			
		||||
                            int *pcyls, int *pheads, int *psecs);
 | 
			
		||||
typedef enum FDriveType {
 | 
			
		||||
    FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
 | 
			
		||||
    FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
 | 
			
		||||
    FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
 | 
			
		||||
    FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
 | 
			
		||||
} FDriveType;
 | 
			
		||||
 | 
			
		||||
typedef enum FDriveRate {
 | 
			
		||||
    FDRIVE_RATE_500K = 0x00,  /* 500 Kbps */
 | 
			
		||||
    FDRIVE_RATE_300K = 0x01,  /* 300 Kbps */
 | 
			
		||||
    FDRIVE_RATE_250K = 0x02,  /* 250 Kbps */
 | 
			
		||||
    FDRIVE_RATE_1M   = 0x03,  /*   1 Mbps */
 | 
			
		||||
} FDriveRate;
 | 
			
		||||
 | 
			
		||||
void bdrv_get_floppy_geometry_hint(BlockDriverState *bs, int *nb_heads,
 | 
			
		||||
                                   int *max_track, int *last_sect,
 | 
			
		||||
                                   FDriveType drive_in, FDriveType *drive,
 | 
			
		||||
                                   FDriveRate *rate);
 | 
			
		||||
int bdrv_get_type_hint(BlockDriverState *bs);
 | 
			
		||||
int bdrv_get_translation_hint(BlockDriverState *bs);
 | 
			
		||||
void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
 | 
			
		||||
                       BlockErrorAction on_write_error);
 | 
			
		||||
BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
 | 
			
		||||
int bdrv_is_removable(BlockDriverState *bs);
 | 
			
		||||
int bdrv_is_read_only(BlockDriverState *bs);
 | 
			
		||||
int bdrv_set_read_only(BlockDriverState *bs, int read_only);
 | 
			
		||||
int bdrv_is_sg(BlockDriverState *bs);
 | 
			
		||||
int bdrv_enable_write_cache(BlockDriverState *bs);
 | 
			
		||||
int bdrv_is_inserted(BlockDriverState *bs);
 | 
			
		||||
int bdrv_media_changed(BlockDriverState *bs);
 | 
			
		||||
void bdrv_lock_medium(BlockDriverState *bs, bool locked);
 | 
			
		||||
void bdrv_eject(BlockDriverState *bs, bool eject_flag);
 | 
			
		||||
int bdrv_is_locked(BlockDriverState *bs);
 | 
			
		||||
void bdrv_set_locked(BlockDriverState *bs, int locked);
 | 
			
		||||
int bdrv_eject(BlockDriverState *bs, int eject_flag);
 | 
			
		||||
void bdrv_set_change_cb(BlockDriverState *bs,
 | 
			
		||||
                        void (*change_cb)(void *opaque), void *opaque);
 | 
			
		||||
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 | 
			
		||||
BlockDriverState *bdrv_find(const char *name);
 | 
			
		||||
BlockDriverState *bdrv_next(BlockDriverState *bs);
 | 
			
		||||
void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs),
 | 
			
		||||
                  void *opaque);
 | 
			
		||||
int bdrv_is_encrypted(BlockDriverState *bs);
 | 
			
		||||
@@ -303,9 +178,6 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
 | 
			
		||||
const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
 | 
			
		||||
void bdrv_get_backing_filename(BlockDriverState *bs,
 | 
			
		||||
                               char *filename, int filename_size);
 | 
			
		||||
int bdrv_can_snapshot(BlockDriverState *bs);
 | 
			
		||||
int bdrv_is_snapshot(BlockDriverState *bs);
 | 
			
		||||
BlockDriverState *bdrv_snapshots(void);
 | 
			
		||||
int bdrv_snapshot_create(BlockDriverState *bs,
 | 
			
		||||
                         QEMUSnapshotInfo *sn_info);
 | 
			
		||||
int bdrv_snapshot_goto(BlockDriverState *bs,
 | 
			
		||||
@@ -313,8 +185,6 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
 | 
			
		||||
int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
 | 
			
		||||
int bdrv_snapshot_list(BlockDriverState *bs,
 | 
			
		||||
                       QEMUSnapshotInfo **psn_info);
 | 
			
		||||
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
 | 
			
		||||
                           const char *snapshot_name);
 | 
			
		||||
char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
 | 
			
		||||
 | 
			
		||||
char *get_human_readable_size(char *buf, int buf_size, int64_t size);
 | 
			
		||||
@@ -329,132 +199,10 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
 | 
			
		||||
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
 | 
			
		||||
                      int64_t pos, int size);
 | 
			
		||||
 | 
			
		||||
int bdrv_img_create(const char *filename, const char *fmt,
 | 
			
		||||
                    const char *base_filename, const char *base_fmt,
 | 
			
		||||
                    char *options, uint64_t img_size, int flags);
 | 
			
		||||
 | 
			
		||||
void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
 | 
			
		||||
void *qemu_blockalign(BlockDriverState *bs, size_t size);
 | 
			
		||||
 | 
			
		||||
#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
 | 
			
		||||
 | 
			
		||||
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
 | 
			
		||||
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
 | 
			
		||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
 | 
			
		||||
                      int nr_sectors);
 | 
			
		||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
void bdrv_enable_copy_on_read(BlockDriverState *bs);
 | 
			
		||||
void bdrv_disable_copy_on_read(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
void bdrv_set_in_use(BlockDriverState *bs, int in_use);
 | 
			
		||||
int bdrv_in_use(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
enum BlockAcctType {
 | 
			
		||||
    BDRV_ACCT_READ,
 | 
			
		||||
    BDRV_ACCT_WRITE,
 | 
			
		||||
    BDRV_ACCT_FLUSH,
 | 
			
		||||
    BDRV_MAX_IOTYPE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct BlockAcctCookie {
 | 
			
		||||
    int64_t bytes;
 | 
			
		||||
    int64_t start_time_ns;
 | 
			
		||||
    enum BlockAcctType type;
 | 
			
		||||
} BlockAcctCookie;
 | 
			
		||||
 | 
			
		||||
void bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
 | 
			
		||||
        int64_t bytes, enum BlockAcctType type);
 | 
			
		||||
void bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie);
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    BLKDBG_L1_UPDATE,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_L1_GROW_ALLOC_TABLE,
 | 
			
		||||
    BLKDBG_L1_GROW_WRITE_TABLE,
 | 
			
		||||
    BLKDBG_L1_GROW_ACTIVATE_TABLE,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_L2_LOAD,
 | 
			
		||||
    BLKDBG_L2_UPDATE,
 | 
			
		||||
    BLKDBG_L2_UPDATE_COMPRESSED,
 | 
			
		||||
    BLKDBG_L2_ALLOC_COW_READ,
 | 
			
		||||
    BLKDBG_L2_ALLOC_WRITE,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_READ,
 | 
			
		||||
    BLKDBG_READ_AIO,
 | 
			
		||||
    BLKDBG_READ_BACKING,
 | 
			
		||||
    BLKDBG_READ_BACKING_AIO,
 | 
			
		||||
    BLKDBG_READ_COMPRESSED,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_WRITE_AIO,
 | 
			
		||||
    BLKDBG_WRITE_COMPRESSED,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_VMSTATE_LOAD,
 | 
			
		||||
    BLKDBG_VMSTATE_SAVE,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_COW_READ,
 | 
			
		||||
    BLKDBG_COW_WRITE,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_REFTABLE_LOAD,
 | 
			
		||||
    BLKDBG_REFTABLE_GROW,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_REFBLOCK_LOAD,
 | 
			
		||||
    BLKDBG_REFBLOCK_UPDATE,
 | 
			
		||||
    BLKDBG_REFBLOCK_UPDATE_PART,
 | 
			
		||||
    BLKDBG_REFBLOCK_ALLOC,
 | 
			
		||||
    BLKDBG_REFBLOCK_ALLOC_HOOKUP,
 | 
			
		||||
    BLKDBG_REFBLOCK_ALLOC_WRITE,
 | 
			
		||||
    BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS,
 | 
			
		||||
    BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE,
 | 
			
		||||
    BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_CLUSTER_ALLOC,
 | 
			
		||||
    BLKDBG_CLUSTER_ALLOC_BYTES,
 | 
			
		||||
    BLKDBG_CLUSTER_FREE,
 | 
			
		||||
 | 
			
		||||
    BLKDBG_EVENT_MAX,
 | 
			
		||||
} BlkDebugEvent;
 | 
			
		||||
 | 
			
		||||
#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
 | 
			
		||||
void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Convenience for block device models */
 | 
			
		||||
 | 
			
		||||
typedef struct BlockConf {
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
    uint16_t physical_block_size;
 | 
			
		||||
    uint16_t logical_block_size;
 | 
			
		||||
    uint16_t min_io_size;
 | 
			
		||||
    uint32_t opt_io_size;
 | 
			
		||||
    int32_t bootindex;
 | 
			
		||||
    uint32_t discard_granularity;
 | 
			
		||||
} BlockConf;
 | 
			
		||||
 | 
			
		||||
static inline unsigned int get_physical_block_exp(BlockConf *conf)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int exp = 0, size;
 | 
			
		||||
 | 
			
		||||
    for (size = conf->physical_block_size;
 | 
			
		||||
        size > conf->logical_block_size;
 | 
			
		||||
        size >>= 1) {
 | 
			
		||||
        exp++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return exp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
 | 
			
		||||
    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
 | 
			
		||||
    DEFINE_PROP_BLOCKSIZE("logical_block_size", _state,                 \
 | 
			
		||||
                          _conf.logical_block_size, 512),               \
 | 
			
		||||
    DEFINE_PROP_BLOCKSIZE("physical_block_size", _state,                \
 | 
			
		||||
                          _conf.physical_block_size, 512),              \
 | 
			
		||||
    DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
 | 
			
		||||
    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
 | 
			
		||||
    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
 | 
			
		||||
    DEFINE_PROP_UINT32("discard_granularity", _state, \
 | 
			
		||||
                       _conf.discard_granularity, 0)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										458
									
								
								block/blkdebug.c
									
									
									
									
									
								
							
							
						
						
									
										458
									
								
								block/blkdebug.c
									
									
									
									
									
								
							@@ -1,458 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Block protocol for I/O error injection
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "module.h"
 | 
			
		||||
 | 
			
		||||
typedef struct BlkdebugVars {
 | 
			
		||||
    int state;
 | 
			
		||||
 | 
			
		||||
    /* If inject_errno != 0, an error is injected for requests */
 | 
			
		||||
    int inject_errno;
 | 
			
		||||
 | 
			
		||||
    /* Decides if all future requests fail (false) or only the next one and
 | 
			
		||||
     * after the next request inject_errno is reset to 0 (true) */
 | 
			
		||||
    bool inject_once;
 | 
			
		||||
 | 
			
		||||
    /* Decides if aio_readv/writev fails right away (true) or returns an error
 | 
			
		||||
     * return value only in the callback (false) */
 | 
			
		||||
    bool inject_immediately;
 | 
			
		||||
} BlkdebugVars;
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVBlkdebugState {
 | 
			
		||||
    BlkdebugVars vars;
 | 
			
		||||
    QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
 | 
			
		||||
} BDRVBlkdebugState;
 | 
			
		||||
 | 
			
		||||
typedef struct BlkdebugAIOCB {
 | 
			
		||||
    BlockDriverAIOCB common;
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
    int ret;
 | 
			
		||||
} BlkdebugAIOCB;
 | 
			
		||||
 | 
			
		||||
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
 | 
			
		||||
 | 
			
		||||
static AIOPool blkdebug_aio_pool = {
 | 
			
		||||
    .aiocb_size = sizeof(BlkdebugAIOCB),
 | 
			
		||||
    .cancel     = blkdebug_aio_cancel,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    ACTION_INJECT_ERROR,
 | 
			
		||||
    ACTION_SET_STATE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct BlkdebugRule {
 | 
			
		||||
    BlkDebugEvent event;
 | 
			
		||||
    int action;
 | 
			
		||||
    int state;
 | 
			
		||||
    union {
 | 
			
		||||
        struct {
 | 
			
		||||
            int error;
 | 
			
		||||
            int immediately;
 | 
			
		||||
            int once;
 | 
			
		||||
        } inject;
 | 
			
		||||
        struct {
 | 
			
		||||
            int new_state;
 | 
			
		||||
        } set_state;
 | 
			
		||||
    } options;
 | 
			
		||||
    QLIST_ENTRY(BlkdebugRule) next;
 | 
			
		||||
} BlkdebugRule;
 | 
			
		||||
 | 
			
		||||
static QemuOptsList inject_error_opts = {
 | 
			
		||||
    .name = "inject-error",
 | 
			
		||||
    .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
 | 
			
		||||
    .desc = {
 | 
			
		||||
        {
 | 
			
		||||
            .name = "event",
 | 
			
		||||
            .type = QEMU_OPT_STRING,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = "state",
 | 
			
		||||
            .type = QEMU_OPT_NUMBER,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = "errno",
 | 
			
		||||
            .type = QEMU_OPT_NUMBER,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = "once",
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = "immediately",
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
        },
 | 
			
		||||
        { /* end of list */ }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static QemuOptsList set_state_opts = {
 | 
			
		||||
    .name = "set-state",
 | 
			
		||||
    .head = QTAILQ_HEAD_INITIALIZER(set_state_opts.head),
 | 
			
		||||
    .desc = {
 | 
			
		||||
        {
 | 
			
		||||
            .name = "event",
 | 
			
		||||
            .type = QEMU_OPT_STRING,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = "state",
 | 
			
		||||
            .type = QEMU_OPT_NUMBER,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = "new_state",
 | 
			
		||||
            .type = QEMU_OPT_NUMBER,
 | 
			
		||||
        },
 | 
			
		||||
        { /* end of list */ }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static QemuOptsList *config_groups[] = {
 | 
			
		||||
    &inject_error_opts,
 | 
			
		||||
    &set_state_opts,
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char *event_names[BLKDBG_EVENT_MAX] = {
 | 
			
		||||
    [BLKDBG_L1_UPDATE]                      = "l1_update",
 | 
			
		||||
    [BLKDBG_L1_GROW_ALLOC_TABLE]            = "l1_grow.alloc_table",
 | 
			
		||||
    [BLKDBG_L1_GROW_WRITE_TABLE]            = "l1_grow.write_table",
 | 
			
		||||
    [BLKDBG_L1_GROW_ACTIVATE_TABLE]         = "l1_grow.activate_table",
 | 
			
		||||
 | 
			
		||||
    [BLKDBG_L2_LOAD]                        = "l2_load",
 | 
			
		||||
    [BLKDBG_L2_UPDATE]                      = "l2_update",
 | 
			
		||||
    [BLKDBG_L2_UPDATE_COMPRESSED]           = "l2_update_compressed",
 | 
			
		||||
    [BLKDBG_L2_ALLOC_COW_READ]              = "l2_alloc.cow_read",
 | 
			
		||||
    [BLKDBG_L2_ALLOC_WRITE]                 = "l2_alloc.write",
 | 
			
		||||
 | 
			
		||||
    [BLKDBG_READ]                           = "read",
 | 
			
		||||
    [BLKDBG_READ_AIO]                       = "read_aio",
 | 
			
		||||
    [BLKDBG_READ_BACKING]                   = "read_backing",
 | 
			
		||||
    [BLKDBG_READ_BACKING_AIO]               = "read_backing_aio",
 | 
			
		||||
    [BLKDBG_READ_COMPRESSED]                = "read_compressed",
 | 
			
		||||
 | 
			
		||||
    [BLKDBG_WRITE_AIO]                      = "write_aio",
 | 
			
		||||
    [BLKDBG_WRITE_COMPRESSED]               = "write_compressed",
 | 
			
		||||
 | 
			
		||||
    [BLKDBG_VMSTATE_LOAD]                   = "vmstate_load",
 | 
			
		||||
    [BLKDBG_VMSTATE_SAVE]                   = "vmstate_save",
 | 
			
		||||
 | 
			
		||||
    [BLKDBG_COW_READ]                       = "cow_read",
 | 
			
		||||
    [BLKDBG_COW_WRITE]                      = "cow_write",
 | 
			
		||||
 | 
			
		||||
    [BLKDBG_REFTABLE_LOAD]                  = "reftable_load",
 | 
			
		||||
    [BLKDBG_REFTABLE_GROW]                  = "reftable_grow",
 | 
			
		||||
 | 
			
		||||
    [BLKDBG_REFBLOCK_LOAD]                  = "refblock_load",
 | 
			
		||||
    [BLKDBG_REFBLOCK_UPDATE]                = "refblock_update",
 | 
			
		||||
    [BLKDBG_REFBLOCK_UPDATE_PART]           = "refblock_update_part",
 | 
			
		||||
    [BLKDBG_REFBLOCK_ALLOC]                 = "refblock_alloc",
 | 
			
		||||
    [BLKDBG_REFBLOCK_ALLOC_HOOKUP]          = "refblock_alloc.hookup",
 | 
			
		||||
    [BLKDBG_REFBLOCK_ALLOC_WRITE]           = "refblock_alloc.write",
 | 
			
		||||
    [BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS]    = "refblock_alloc.write_blocks",
 | 
			
		||||
    [BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE]     = "refblock_alloc.write_table",
 | 
			
		||||
    [BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE]    = "refblock_alloc.switch_table",
 | 
			
		||||
 | 
			
		||||
    [BLKDBG_CLUSTER_ALLOC]                  = "cluster_alloc",
 | 
			
		||||
    [BLKDBG_CLUSTER_ALLOC_BYTES]            = "cluster_alloc_bytes",
 | 
			
		||||
    [BLKDBG_CLUSTER_FREE]                   = "cluster_free",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int get_event_by_name(const char *name, BlkDebugEvent *event)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
 | 
			
		||||
        if (!strcmp(event_names[i], name)) {
 | 
			
		||||
            *event = i;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct add_rule_data {
 | 
			
		||||
    BDRVBlkdebugState *s;
 | 
			
		||||
    int action;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int add_rule(QemuOpts *opts, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    struct add_rule_data *d = opaque;
 | 
			
		||||
    BDRVBlkdebugState *s = d->s;
 | 
			
		||||
    const char* event_name;
 | 
			
		||||
    BlkDebugEvent event;
 | 
			
		||||
    struct BlkdebugRule *rule;
 | 
			
		||||
 | 
			
		||||
    /* Find the right event for the rule */
 | 
			
		||||
    event_name = qemu_opt_get(opts, "event");
 | 
			
		||||
    if (!event_name || get_event_by_name(event_name, &event) < 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Set attributes common for all actions */
 | 
			
		||||
    rule = g_malloc0(sizeof(*rule));
 | 
			
		||||
    *rule = (struct BlkdebugRule) {
 | 
			
		||||
        .event  = event,
 | 
			
		||||
        .action = d->action,
 | 
			
		||||
        .state  = qemu_opt_get_number(opts, "state", 0),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /* Parse action-specific options */
 | 
			
		||||
    switch (d->action) {
 | 
			
		||||
    case ACTION_INJECT_ERROR:
 | 
			
		||||
        rule->options.inject.error = qemu_opt_get_number(opts, "errno", EIO);
 | 
			
		||||
        rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
 | 
			
		||||
        rule->options.inject.immediately =
 | 
			
		||||
            qemu_opt_get_bool(opts, "immediately", 0);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case ACTION_SET_STATE:
 | 
			
		||||
        rule->options.set_state.new_state =
 | 
			
		||||
            qemu_opt_get_number(opts, "new_state", 0);
 | 
			
		||||
        break;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /* Add the rule */
 | 
			
		||||
    QLIST_INSERT_HEAD(&s->rules[event], rule, next);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int read_config(BDRVBlkdebugState *s, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
    FILE *f;
 | 
			
		||||
    int ret;
 | 
			
		||||
    struct add_rule_data d;
 | 
			
		||||
 | 
			
		||||
    f = fopen(filename, "r");
 | 
			
		||||
    if (f == NULL) {
 | 
			
		||||
        return -errno;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = qemu_config_parse(f, config_groups, filename);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    d.s = s;
 | 
			
		||||
    d.action = ACTION_INJECT_ERROR;
 | 
			
		||||
    qemu_opts_foreach(&inject_error_opts, add_rule, &d, 0);
 | 
			
		||||
 | 
			
		||||
    d.action = ACTION_SET_STATE;
 | 
			
		||||
    qemu_opts_foreach(&set_state_opts, add_rule, &d, 0);
 | 
			
		||||
 | 
			
		||||
    ret = 0;
 | 
			
		||||
fail:
 | 
			
		||||
    qemu_opts_reset(&inject_error_opts);
 | 
			
		||||
    qemu_opts_reset(&set_state_opts);
 | 
			
		||||
    fclose(f);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
 | 
			
		||||
static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
			
		||||
    int ret;
 | 
			
		||||
    char *config, *c;
 | 
			
		||||
 | 
			
		||||
    /* Parse the blkdebug: prefix */
 | 
			
		||||
    if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
    filename += strlen("blkdebug:");
 | 
			
		||||
 | 
			
		||||
    /* Read rules from config file */
 | 
			
		||||
    c = strchr(filename, ':');
 | 
			
		||||
    if (c == NULL) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    config = g_strdup(filename);
 | 
			
		||||
    config[c - filename] = '\0';
 | 
			
		||||
    ret = read_config(s, config);
 | 
			
		||||
    g_free(config);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    filename = c + 1;
 | 
			
		||||
 | 
			
		||||
    /* Set initial state */
 | 
			
		||||
    s->vars.state = 1;
 | 
			
		||||
 | 
			
		||||
    /* Open the backing file */
 | 
			
		||||
    ret = bdrv_file_open(&bs->file, filename, flags);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void error_callback_bh(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    struct BlkdebugAIOCB *acb = opaque;
 | 
			
		||||
    qemu_bh_delete(acb->bh);
 | 
			
		||||
    acb->common.cb(acb->common.opaque, acb->ret);
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
 | 
			
		||||
{
 | 
			
		||||
    BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
 | 
			
		||||
    BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
			
		||||
    int error = s->vars.inject_errno;
 | 
			
		||||
    struct BlkdebugAIOCB *acb;
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
 | 
			
		||||
    if (s->vars.inject_once) {
 | 
			
		||||
        s->vars.inject_errno = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->vars.inject_immediately) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
 | 
			
		||||
    acb->ret = -error;
 | 
			
		||||
 | 
			
		||||
    bh = qemu_bh_new(error_callback_bh, acb);
 | 
			
		||||
    acb->bh = bh;
 | 
			
		||||
    qemu_bh_schedule(bh);
 | 
			
		||||
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
 | 
			
		||||
    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
    BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    if (s->vars.inject_errno) {
 | 
			
		||||
        return inject_error(bs, cb, opaque);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BlockDriverAIOCB *acb =
 | 
			
		||||
        bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
 | 
			
		||||
    return acb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
 | 
			
		||||
    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
    BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    if (s->vars.inject_errno) {
 | 
			
		||||
        return inject_error(bs, cb, opaque);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BlockDriverAIOCB *acb =
 | 
			
		||||
        bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
 | 
			
		||||
    return acb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkdebug_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
			
		||||
    BlkdebugRule *rule, *next;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
 | 
			
		||||
        QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
 | 
			
		||||
            QLIST_REMOVE(rule, next);
 | 
			
		||||
            g_free(rule);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
 | 
			
		||||
    BlkdebugVars *old_vars)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
			
		||||
    BlkdebugVars *vars = &s->vars;
 | 
			
		||||
 | 
			
		||||
    /* Only process rules for the current state */
 | 
			
		||||
    if (rule->state && rule->state != old_vars->state) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Take the action */
 | 
			
		||||
    switch (rule->action) {
 | 
			
		||||
    case ACTION_INJECT_ERROR:
 | 
			
		||||
        vars->inject_errno       = rule->options.inject.error;
 | 
			
		||||
        vars->inject_once        = rule->options.inject.once;
 | 
			
		||||
        vars->inject_immediately = rule->options.inject.immediately;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case ACTION_SET_STATE:
 | 
			
		||||
        vars->state              = rule->options.set_state.new_state;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
			
		||||
    struct BlkdebugRule *rule;
 | 
			
		||||
    BlkdebugVars old_vars = s->vars;
 | 
			
		||||
 | 
			
		||||
    assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
 | 
			
		||||
 | 
			
		||||
    QLIST_FOREACH(rule, &s->rules[event], next) {
 | 
			
		||||
        process_rule(bs, rule, &old_vars);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_blkdebug = {
 | 
			
		||||
    .format_name        = "blkdebug",
 | 
			
		||||
    .protocol_name      = "blkdebug",
 | 
			
		||||
 | 
			
		||||
    .instance_size      = sizeof(BDRVBlkdebugState),
 | 
			
		||||
 | 
			
		||||
    .bdrv_file_open     = blkdebug_open,
 | 
			
		||||
    .bdrv_close         = blkdebug_close,
 | 
			
		||||
 | 
			
		||||
    .bdrv_aio_readv     = blkdebug_aio_readv,
 | 
			
		||||
    .bdrv_aio_writev    = blkdebug_aio_writev,
 | 
			
		||||
 | 
			
		||||
    .bdrv_debug_event   = blkdebug_debug_event,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void bdrv_blkdebug_init(void)
 | 
			
		||||
{
 | 
			
		||||
    bdrv_register(&bdrv_blkdebug);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
block_init(bdrv_blkdebug_init);
 | 
			
		||||
@@ -1,366 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Block protocol for block driver correctness testing
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2010 IBM, Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 <stdarg.h>
 | 
			
		||||
#include "qemu_socket.h" /* for EINPROGRESS on Windows */
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    BlockDriverState *test_file;
 | 
			
		||||
} BDRVBlkverifyState;
 | 
			
		||||
 | 
			
		||||
typedef struct BlkverifyAIOCB BlkverifyAIOCB;
 | 
			
		||||
struct BlkverifyAIOCB {
 | 
			
		||||
    BlockDriverAIOCB common;
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
 | 
			
		||||
    /* Request metadata */
 | 
			
		||||
    bool is_write;
 | 
			
		||||
    int64_t sector_num;
 | 
			
		||||
    int nb_sectors;
 | 
			
		||||
 | 
			
		||||
    int ret;                    /* first completed request's result */
 | 
			
		||||
    unsigned int done;          /* completion counter */
 | 
			
		||||
    bool *finished;             /* completion signal for cancel */
 | 
			
		||||
 | 
			
		||||
    QEMUIOVector *qiov;         /* user I/O vector */
 | 
			
		||||
    QEMUIOVector raw_qiov;      /* cloned I/O vector for raw file */
 | 
			
		||||
    void *buf;                  /* buffer for raw file I/O */
 | 
			
		||||
 | 
			
		||||
    void (*verify)(BlkverifyAIOCB *acb);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb)
 | 
			
		||||
{
 | 
			
		||||
    BlkverifyAIOCB *acb = (BlkverifyAIOCB *)blockacb;
 | 
			
		||||
    bool finished = false;
 | 
			
		||||
 | 
			
		||||
    /* Wait until request completes, invokes its callback, and frees itself */
 | 
			
		||||
    acb->finished = &finished;
 | 
			
		||||
    while (!finished) {
 | 
			
		||||
        qemu_aio_wait();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static AIOPool blkverify_aio_pool = {
 | 
			
		||||
    .aiocb_size         = sizeof(BlkverifyAIOCB),
 | 
			
		||||
    .cancel             = blkverify_aio_cancel,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
 | 
			
		||||
                                             const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
    va_list ap;
 | 
			
		||||
 | 
			
		||||
    va_start(ap, fmt);
 | 
			
		||||
    fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ",
 | 
			
		||||
            acb->is_write ? "write" : "read", acb->sector_num,
 | 
			
		||||
            acb->nb_sectors);
 | 
			
		||||
    vfprintf(stderr, fmt, ap);
 | 
			
		||||
    fprintf(stderr, "\n");
 | 
			
		||||
    va_end(ap);
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
 | 
			
		||||
static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkverifyState *s = bs->opaque;
 | 
			
		||||
    int ret;
 | 
			
		||||
    char *raw, *c;
 | 
			
		||||
 | 
			
		||||
    /* Parse the blkverify: prefix */
 | 
			
		||||
    if (strncmp(filename, "blkverify:", strlen("blkverify:"))) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
    filename += strlen("blkverify:");
 | 
			
		||||
 | 
			
		||||
    /* Parse the raw image filename */
 | 
			
		||||
    c = strchr(filename, ':');
 | 
			
		||||
    if (c == NULL) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    raw = g_strdup(filename);
 | 
			
		||||
    raw[c - filename] = '\0';
 | 
			
		||||
    ret = bdrv_file_open(&bs->file, raw, flags);
 | 
			
		||||
    g_free(raw);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    filename = c + 1;
 | 
			
		||||
 | 
			
		||||
    /* Open the test file */
 | 
			
		||||
    s->test_file = bdrv_new("");
 | 
			
		||||
    ret = bdrv_open(s->test_file, filename, flags, NULL);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        bdrv_delete(s->test_file);
 | 
			
		||||
        s->test_file = NULL;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkverify_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkverifyState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    bdrv_delete(s->test_file);
 | 
			
		||||
    s->test_file = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t blkverify_getlength(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkverifyState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    return bdrv_getlength(s->test_file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check that I/O vector contents are identical
 | 
			
		||||
 *
 | 
			
		||||
 * @a:          I/O vector
 | 
			
		||||
 * @b:          I/O vector
 | 
			
		||||
 * @ret:        Offset to first mismatching byte or -1 if match
 | 
			
		||||
 */
 | 
			
		||||
static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    ssize_t offset = 0;
 | 
			
		||||
 | 
			
		||||
    assert(a->niov == b->niov);
 | 
			
		||||
    for (i = 0; i < a->niov; i++) {
 | 
			
		||||
        size_t len = 0;
 | 
			
		||||
        uint8_t *p = (uint8_t *)a->iov[i].iov_base;
 | 
			
		||||
        uint8_t *q = (uint8_t *)b->iov[i].iov_base;
 | 
			
		||||
 | 
			
		||||
        assert(a->iov[i].iov_len == b->iov[i].iov_len);
 | 
			
		||||
        while (len < a->iov[i].iov_len && *p++ == *q++) {
 | 
			
		||||
            len++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        offset += len;
 | 
			
		||||
 | 
			
		||||
        if (len != a->iov[i].iov_len) {
 | 
			
		||||
            return offset;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int src_index;
 | 
			
		||||
    struct iovec *src_iov;
 | 
			
		||||
    void *dest_base;
 | 
			
		||||
} IOVectorSortElem;
 | 
			
		||||
 | 
			
		||||
static int sortelem_cmp_src_base(const void *a, const void *b)
 | 
			
		||||
{
 | 
			
		||||
    const IOVectorSortElem *elem_a = a;
 | 
			
		||||
    const IOVectorSortElem *elem_b = b;
 | 
			
		||||
 | 
			
		||||
    /* Don't overflow */
 | 
			
		||||
    if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    } else {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sortelem_cmp_src_index(const void *a, const void *b)
 | 
			
		||||
{
 | 
			
		||||
    const IOVectorSortElem *elem_a = a;
 | 
			
		||||
    const IOVectorSortElem *elem_b = b;
 | 
			
		||||
 | 
			
		||||
    return elem_a->src_index - elem_b->src_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Copy contents of I/O vector
 | 
			
		||||
 *
 | 
			
		||||
 * The relative relationships of overlapping iovecs are preserved.  This is
 | 
			
		||||
 * necessary to ensure identical semantics in the cloned I/O vector.
 | 
			
		||||
 */
 | 
			
		||||
static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src,
 | 
			
		||||
                                  void *buf)
 | 
			
		||||
{
 | 
			
		||||
    IOVectorSortElem sortelems[src->niov];
 | 
			
		||||
    void *last_end;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    /* Sort by source iovecs by base address */
 | 
			
		||||
    for (i = 0; i < src->niov; i++) {
 | 
			
		||||
        sortelems[i].src_index = i;
 | 
			
		||||
        sortelems[i].src_iov = &src->iov[i];
 | 
			
		||||
    }
 | 
			
		||||
    qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base);
 | 
			
		||||
 | 
			
		||||
    /* Allocate buffer space taking into account overlapping iovecs */
 | 
			
		||||
    last_end = NULL;
 | 
			
		||||
    for (i = 0; i < src->niov; i++) {
 | 
			
		||||
        struct iovec *cur = sortelems[i].src_iov;
 | 
			
		||||
        ptrdiff_t rewind = 0;
 | 
			
		||||
 | 
			
		||||
        /* Detect overlap */
 | 
			
		||||
        if (last_end && last_end > cur->iov_base) {
 | 
			
		||||
            rewind = last_end - cur->iov_base;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sortelems[i].dest_base = buf - rewind;
 | 
			
		||||
        buf += cur->iov_len - MIN(rewind, cur->iov_len);
 | 
			
		||||
        last_end = MAX(cur->iov_base + cur->iov_len, last_end);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Sort by source iovec index and build destination iovec */
 | 
			
		||||
    qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index);
 | 
			
		||||
    for (i = 0; i < src->niov; i++) {
 | 
			
		||||
        qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
 | 
			
		||||
                                         int64_t sector_num, QEMUIOVector *qiov,
 | 
			
		||||
                                         int nb_sectors,
 | 
			
		||||
                                         BlockDriverCompletionFunc *cb,
 | 
			
		||||
                                         void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
 | 
			
		||||
 | 
			
		||||
    acb->bh = NULL;
 | 
			
		||||
    acb->is_write = is_write;
 | 
			
		||||
    acb->sector_num = sector_num;
 | 
			
		||||
    acb->nb_sectors = nb_sectors;
 | 
			
		||||
    acb->ret = -EINPROGRESS;
 | 
			
		||||
    acb->done = 0;
 | 
			
		||||
    acb->qiov = qiov;
 | 
			
		||||
    acb->buf = NULL;
 | 
			
		||||
    acb->verify = NULL;
 | 
			
		||||
    acb->finished = NULL;
 | 
			
		||||
    return acb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkverify_aio_bh(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BlkverifyAIOCB *acb = opaque;
 | 
			
		||||
 | 
			
		||||
    qemu_bh_delete(acb->bh);
 | 
			
		||||
    if (acb->buf) {
 | 
			
		||||
        qemu_iovec_destroy(&acb->raw_qiov);
 | 
			
		||||
        qemu_vfree(acb->buf);
 | 
			
		||||
    }
 | 
			
		||||
    acb->common.cb(acb->common.opaque, acb->ret);
 | 
			
		||||
    if (acb->finished) {
 | 
			
		||||
        *acb->finished = true;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkverify_aio_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    BlkverifyAIOCB *acb = opaque;
 | 
			
		||||
 | 
			
		||||
    switch (++acb->done) {
 | 
			
		||||
    case 1:
 | 
			
		||||
        acb->ret = ret;
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 2:
 | 
			
		||||
        if (acb->ret != ret) {
 | 
			
		||||
            blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (acb->verify) {
 | 
			
		||||
            acb->verify(acb);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        acb->bh = qemu_bh_new(blkverify_aio_bh, acb);
 | 
			
		||||
        qemu_bh_schedule(acb->bh);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void blkverify_verify_readv(BlkverifyAIOCB *acb)
 | 
			
		||||
{
 | 
			
		||||
    ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
 | 
			
		||||
    if (offset != -1) {
 | 
			
		||||
        blkverify_err(acb, "contents mismatch in sector %" PRId64,
 | 
			
		||||
                      acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkverifyState *s = bs->opaque;
 | 
			
		||||
    BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
 | 
			
		||||
                                            nb_sectors, cb, opaque);
 | 
			
		||||
 | 
			
		||||
    acb->verify = blkverify_verify_readv;
 | 
			
		||||
    acb->buf = qemu_blockalign(bs->file, qiov->size);
 | 
			
		||||
    qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
 | 
			
		||||
    blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
 | 
			
		||||
 | 
			
		||||
    bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
 | 
			
		||||
                   blkverify_aio_cb, acb);
 | 
			
		||||
    bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
 | 
			
		||||
                   blkverify_aio_cb, acb);
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkverifyState *s = bs->opaque;
 | 
			
		||||
    BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
 | 
			
		||||
                                            nb_sectors, cb, opaque);
 | 
			
		||||
 | 
			
		||||
    bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
 | 
			
		||||
                    blkverify_aio_cb, acb);
 | 
			
		||||
    bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
 | 
			
		||||
                    blkverify_aio_cb, acb);
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
 | 
			
		||||
                                             BlockDriverCompletionFunc *cb,
 | 
			
		||||
                                             void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBlkverifyState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    /* Only flush test file, the raw file is not important */
 | 
			
		||||
    return bdrv_aio_flush(s->test_file, cb, opaque);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_blkverify = {
 | 
			
		||||
    .format_name        = "blkverify",
 | 
			
		||||
    .protocol_name      = "blkverify",
 | 
			
		||||
 | 
			
		||||
    .instance_size      = sizeof(BDRVBlkverifyState),
 | 
			
		||||
 | 
			
		||||
    .bdrv_getlength     = blkverify_getlength,
 | 
			
		||||
 | 
			
		||||
    .bdrv_file_open     = blkverify_open,
 | 
			
		||||
    .bdrv_close         = blkverify_close,
 | 
			
		||||
 | 
			
		||||
    .bdrv_aio_readv     = blkverify_aio_readv,
 | 
			
		||||
    .bdrv_aio_writev    = blkverify_aio_writev,
 | 
			
		||||
    .bdrv_aio_flush     = blkverify_aio_flush,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void bdrv_blkverify_init(void)
 | 
			
		||||
{
 | 
			
		||||
    bdrv_register(&bdrv_blkverify);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
block_init(bdrv_blkverify_init);
 | 
			
		||||
@@ -80,7 +80,8 @@ struct bochs_header {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVBochsState {
 | 
			
		||||
    CoMutex lock;
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    uint32_t *catalog_bitmap;
 | 
			
		||||
    int catalog_size;
 | 
			
		||||
 | 
			
		||||
@@ -108,16 +109,25 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int bochs_open(BlockDriverState *bs, int flags)
 | 
			
		||||
static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBochsState *s = bs->opaque;
 | 
			
		||||
    int i;
 | 
			
		||||
    int fd, i;
 | 
			
		||||
    struct bochs_header bochs;
 | 
			
		||||
    struct bochs_header_v1 header_v1;
 | 
			
		||||
 | 
			
		||||
    fd = open(filename, O_RDWR | O_BINARY);
 | 
			
		||||
    if (fd < 0) {
 | 
			
		||||
        fd = open(filename, O_RDONLY | O_BINARY);
 | 
			
		||||
        if (fd < 0)
 | 
			
		||||
            return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bs->read_only = 1; // no write support yet
 | 
			
		||||
 | 
			
		||||
    if (bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)) != sizeof(bochs)) {
 | 
			
		||||
    s->fd = fd;
 | 
			
		||||
 | 
			
		||||
    if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -136,10 +146,12 @@ static int bochs_open(BlockDriverState *bs, int flags)
 | 
			
		||||
      bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
 | 
			
		||||
 | 
			
		||||
    s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
 | 
			
		||||
    s->catalog_bitmap = g_malloc(s->catalog_size * 4);
 | 
			
		||||
    if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
 | 
			
		||||
                   s->catalog_size * 4) != s->catalog_size * 4)
 | 
			
		||||
    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
 | 
			
		||||
    if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
 | 
			
		||||
	s->catalog_size * 4)
 | 
			
		||||
	goto fail;
 | 
			
		||||
    for (i = 0; i < s->catalog_size; i++)
 | 
			
		||||
	le32_to_cpus(&s->catalog_bitmap[i]);
 | 
			
		||||
@@ -151,56 +163,70 @@ static int bochs_open(BlockDriverState *bs, int flags)
 | 
			
		||||
 | 
			
		||||
    s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
 | 
			
		||||
 | 
			
		||||
    qemu_co_mutex_init(&s->lock);
 | 
			
		||||
    return 0;
 | 
			
		||||
 fail:
 | 
			
		||||
    close(fd);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
 | 
			
		||||
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBochsState *s = bs->opaque;
 | 
			
		||||
    int64_t offset = sector_num * 512;
 | 
			
		||||
    int64_t extent_index, extent_offset, bitmap_offset;
 | 
			
		||||
    int64_t extent_index, extent_offset, bitmap_offset, block_offset;
 | 
			
		||||
    char bitmap_entry;
 | 
			
		||||
 | 
			
		||||
    // seek to sector
 | 
			
		||||
    extent_index = offset / s->extent_size;
 | 
			
		||||
    extent_offset = (offset % s->extent_size) / 512;
 | 
			
		||||
 | 
			
		||||
    if (s->catalog_bitmap[extent_index] == 0xffffffff) {
 | 
			
		||||
	return -1; /* not allocated */
 | 
			
		||||
    if (s->catalog_bitmap[extent_index] == 0xffffffff)
 | 
			
		||||
    {
 | 
			
		||||
//	fprintf(stderr, "page not allocated [%x - %x:%x]\n",
 | 
			
		||||
//	    sector_num, extent_index, extent_offset);
 | 
			
		||||
	return -1; // not allocated
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
 | 
			
		||||
	(s->extent_blocks + s->bitmap_blocks));
 | 
			
		||||
    block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
 | 
			
		||||
 | 
			
		||||
    /* read in bitmap for current extent */
 | 
			
		||||
    if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
 | 
			
		||||
                   &bitmap_entry, 1) != 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
//    fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
 | 
			
		||||
//	sector_num, extent_index, extent_offset,
 | 
			
		||||
//	le32_to_cpu(s->catalog_bitmap[extent_index]),
 | 
			
		||||
//	bitmap_offset, block_offset);
 | 
			
		||||
 | 
			
		||||
    // read in bitmap for current extent
 | 
			
		||||
    lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET);
 | 
			
		||||
 | 
			
		||||
    read(s->fd, &bitmap_entry, 1);
 | 
			
		||||
 | 
			
		||||
    if (!((bitmap_entry >> (extent_offset % 8)) & 1))
 | 
			
		||||
    {
 | 
			
		||||
//	fprintf(stderr, "sector (%x) in bitmap not allocated\n",
 | 
			
		||||
//	    sector_num);
 | 
			
		||||
	return -1; // not allocated
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
 | 
			
		||||
	return -1; /* not allocated */
 | 
			
		||||
    }
 | 
			
		||||
    lseek(s->fd, block_offset, SEEK_SET);
 | 
			
		||||
 | 
			
		||||
    return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                    uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBochsState *s = bs->opaque;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    while (nb_sectors > 0) {
 | 
			
		||||
        int64_t block_offset = seek_to_sector(bs, sector_num);
 | 
			
		||||
        if (block_offset >= 0) {
 | 
			
		||||
            ret = bdrv_pread(bs->file, block_offset, buf, 512);
 | 
			
		||||
            if (ret != 512) {
 | 
			
		||||
	if (!seek_to_sector(bs, sector_num))
 | 
			
		||||
	{
 | 
			
		||||
	    ret = read(s->fd, buf, 512);
 | 
			
		||||
	    if (ret != 512)
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
        } else
 | 
			
		||||
	else
 | 
			
		||||
            memset(buf, 0, 512);
 | 
			
		||||
        nb_sectors--;
 | 
			
		||||
        sector_num++;
 | 
			
		||||
@@ -209,21 +235,11 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static coroutine_fn int bochs_co_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                      uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    BDRVBochsState *s = bs->opaque;
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
    ret = bochs_read(bs, sector_num, buf, nb_sectors);
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void bochs_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVBochsState *s = bs->opaque;
 | 
			
		||||
    g_free(s->catalog_bitmap);
 | 
			
		||||
    qemu_free(s->catalog_bitmap);
 | 
			
		||||
    close(s->fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_bochs = {
 | 
			
		||||
@@ -231,7 +247,7 @@ static BlockDriver bdrv_bochs = {
 | 
			
		||||
    .instance_size	= sizeof(BDRVBochsState),
 | 
			
		||||
    .bdrv_probe		= bochs_probe,
 | 
			
		||||
    .bdrv_open		= bochs_open,
 | 
			
		||||
    .bdrv_read          = bochs_co_read,
 | 
			
		||||
    .bdrv_read		= bochs_read,
 | 
			
		||||
    .bdrv_close		= bochs_close,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										130
									
								
								block/cloop.c
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								block/cloop.c
									
									
									
									
									
								
							@@ -27,10 +27,10 @@
 | 
			
		||||
#include <zlib.h>
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVCloopState {
 | 
			
		||||
    CoMutex lock;
 | 
			
		||||
    int fd;
 | 
			
		||||
    uint32_t block_size;
 | 
			
		||||
    uint32_t n_blocks;
 | 
			
		||||
    uint64_t *offsets;
 | 
			
		||||
    uint64_t* offsets;
 | 
			
		||||
    uint32_t sectors_per_block;
 | 
			
		||||
    uint32_t current_block;
 | 
			
		||||
    uint8_t *compressed_block;
 | 
			
		||||
@@ -40,97 +40,87 @@ typedef struct BDRVCloopState {
 | 
			
		||||
 | 
			
		||||
static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
    const char *magic_version_2_0 = "#!/bin/sh\n"
 | 
			
		||||
    const char* magic_version_2_0="#!/bin/sh\n"
 | 
			
		||||
	"#V2.0 Format\n"
 | 
			
		||||
	"modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
 | 
			
		||||
    int length = strlen(magic_version_2_0);
 | 
			
		||||
    if (length > buf_size) {
 | 
			
		||||
        length = buf_size;
 | 
			
		||||
    }
 | 
			
		||||
    if (!memcmp(magic_version_2_0, buf, length)) {
 | 
			
		||||
    int length=strlen(magic_version_2_0);
 | 
			
		||||
    if(length>buf_size)
 | 
			
		||||
	length=buf_size;
 | 
			
		||||
    if(!memcmp(magic_version_2_0,buf,length))
 | 
			
		||||
	return 2;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cloop_open(BlockDriverState *bs, int flags)
 | 
			
		||||
static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCloopState *s = bs->opaque;
 | 
			
		||||
    uint32_t offsets_size, max_compressed_block_size = 1, i;
 | 
			
		||||
    uint32_t offsets_size,max_compressed_block_size=1,i;
 | 
			
		||||
 | 
			
		||||
    s->fd = open(filename, O_RDONLY | O_BINARY);
 | 
			
		||||
    if (s->fd < 0)
 | 
			
		||||
        return -errno;
 | 
			
		||||
    bs->read_only = 1;
 | 
			
		||||
 | 
			
		||||
    /* read header */
 | 
			
		||||
    if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) {
 | 
			
		||||
        goto cloop_close;
 | 
			
		||||
    if(lseek(s->fd,128,SEEK_SET)<0) {
 | 
			
		||||
cloop_close:
 | 
			
		||||
	close(s->fd);
 | 
			
		||||
	return -1;
 | 
			
		||||
    }
 | 
			
		||||
    s->block_size = be32_to_cpu(s->block_size);
 | 
			
		||||
 | 
			
		||||
    if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) {
 | 
			
		||||
    if(read(s->fd,&s->block_size,4)<4)
 | 
			
		||||
	goto cloop_close;
 | 
			
		||||
    }
 | 
			
		||||
    s->n_blocks = be32_to_cpu(s->n_blocks);
 | 
			
		||||
    s->block_size=be32_to_cpu(s->block_size);
 | 
			
		||||
    if(read(s->fd,&s->n_blocks,4)<4)
 | 
			
		||||
	goto cloop_close;
 | 
			
		||||
    s->n_blocks=be32_to_cpu(s->n_blocks);
 | 
			
		||||
 | 
			
		||||
    /* read offsets */
 | 
			
		||||
    offsets_size = s->n_blocks * sizeof(uint64_t);
 | 
			
		||||
    s->offsets = g_malloc(offsets_size);
 | 
			
		||||
    if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
 | 
			
		||||
            offsets_size) {
 | 
			
		||||
    offsets_size=s->n_blocks*sizeof(uint64_t);
 | 
			
		||||
    s->offsets=(uint64_t*)qemu_malloc(offsets_size);
 | 
			
		||||
    if(read(s->fd,s->offsets,offsets_size)<offsets_size)
 | 
			
		||||
	goto cloop_close;
 | 
			
		||||
    }
 | 
			
		||||
    for(i=0;i<s->n_blocks;i++) {
 | 
			
		||||
        s->offsets[i] = be64_to_cpu(s->offsets[i]);
 | 
			
		||||
        if (i > 0) {
 | 
			
		||||
            uint32_t size = s->offsets[i] - s->offsets[i - 1];
 | 
			
		||||
            if (size > max_compressed_block_size) {
 | 
			
		||||
                max_compressed_block_size = size;
 | 
			
		||||
            }
 | 
			
		||||
	s->offsets[i]=be64_to_cpu(s->offsets[i]);
 | 
			
		||||
	if(i>0) {
 | 
			
		||||
	    uint32_t size=s->offsets[i]-s->offsets[i-1];
 | 
			
		||||
	    if(size>max_compressed_block_size)
 | 
			
		||||
		max_compressed_block_size=size;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* initialize zlib engine */
 | 
			
		||||
    s->compressed_block = g_malloc(max_compressed_block_size + 1);
 | 
			
		||||
    s->uncompressed_block = g_malloc(s->block_size);
 | 
			
		||||
    if (inflateInit(&s->zstream) != Z_OK) {
 | 
			
		||||
    s->compressed_block = qemu_malloc(max_compressed_block_size+1);
 | 
			
		||||
    s->uncompressed_block = qemu_malloc(s->block_size);
 | 
			
		||||
    if(inflateInit(&s->zstream) != Z_OK)
 | 
			
		||||
	goto cloop_close;
 | 
			
		||||
    }
 | 
			
		||||
    s->current_block = s->n_blocks;
 | 
			
		||||
    s->current_block=s->n_blocks;
 | 
			
		||||
 | 
			
		||||
    s->sectors_per_block = s->block_size/512;
 | 
			
		||||
    bs->total_sectors = s->n_blocks * s->sectors_per_block;
 | 
			
		||||
    qemu_co_mutex_init(&s->lock);
 | 
			
		||||
    bs->total_sectors = s->n_blocks*s->sectors_per_block;
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
cloop_close:
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int cloop_read_block(BlockDriverState *bs, int block_num)
 | 
			
		||||
static inline int cloop_read_block(BDRVCloopState *s,int block_num)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCloopState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    if (s->current_block != block_num) {
 | 
			
		||||
    if(s->current_block != block_num) {
 | 
			
		||||
	int ret;
 | 
			
		||||
        uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
 | 
			
		||||
        uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
 | 
			
		||||
 | 
			
		||||
        ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
 | 
			
		||||
                         bytes);
 | 
			
		||||
        if (ret != bytes) {
 | 
			
		||||
	lseek(s->fd, s->offsets[block_num], SEEK_SET);
 | 
			
		||||
        ret = read(s->fd, s->compressed_block, bytes);
 | 
			
		||||
        if (ret != bytes)
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	s->zstream.next_in = s->compressed_block;
 | 
			
		||||
	s->zstream.avail_in = bytes;
 | 
			
		||||
	s->zstream.next_out = s->uncompressed_block;
 | 
			
		||||
	s->zstream.avail_out = s->block_size;
 | 
			
		||||
	ret = inflateReset(&s->zstream);
 | 
			
		||||
        if (ret != Z_OK) {
 | 
			
		||||
	if(ret != Z_OK)
 | 
			
		||||
	    return -1;
 | 
			
		||||
        }
 | 
			
		||||
	ret = inflate(&s->zstream, Z_FINISH);
 | 
			
		||||
        if (ret != Z_STREAM_END || s->zstream.total_out != s->block_size) {
 | 
			
		||||
	if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
 | 
			
		||||
	    return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	s->current_block = block_num;
 | 
			
		||||
    }
 | 
			
		||||
@@ -143,38 +133,24 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    BDRVCloopState *s = bs->opaque;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < nb_sectors; i++) {
 | 
			
		||||
        uint32_t sector_offset_in_block =
 | 
			
		||||
            ((sector_num + i) % s->sectors_per_block),
 | 
			
		||||
            block_num = (sector_num + i) / s->sectors_per_block;
 | 
			
		||||
        if (cloop_read_block(bs, block_num) != 0) {
 | 
			
		||||
    for(i=0;i<nb_sectors;i++) {
 | 
			
		||||
	uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
 | 
			
		||||
	    block_num=(sector_num+i)/s->sectors_per_block;
 | 
			
		||||
	if(cloop_read_block(s, block_num) != 0)
 | 
			
		||||
	    return -1;
 | 
			
		||||
        }
 | 
			
		||||
        memcpy(buf + i * 512,
 | 
			
		||||
            s->uncompressed_block + sector_offset_in_block * 512, 512);
 | 
			
		||||
	memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                      uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    BDRVCloopState *s = bs->opaque;
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
    ret = cloop_read(bs, sector_num, buf, nb_sectors);
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cloop_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCloopState *s = bs->opaque;
 | 
			
		||||
    if (s->n_blocks > 0) {
 | 
			
		||||
        g_free(s->offsets);
 | 
			
		||||
    }
 | 
			
		||||
    g_free(s->compressed_block);
 | 
			
		||||
    g_free(s->uncompressed_block);
 | 
			
		||||
    close(s->fd);
 | 
			
		||||
    if(s->n_blocks>0)
 | 
			
		||||
	free(s->offsets);
 | 
			
		||||
    free(s->compressed_block);
 | 
			
		||||
    free(s->uncompressed_block);
 | 
			
		||||
    inflateEnd(&s->zstream);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -183,7 +159,7 @@ static BlockDriver bdrv_cloop = {
 | 
			
		||||
    .instance_size	= sizeof(BDRVCloopState),
 | 
			
		||||
    .bdrv_probe		= cloop_probe,
 | 
			
		||||
    .bdrv_open		= cloop_open,
 | 
			
		||||
    .bdrv_read      = cloop_co_read,
 | 
			
		||||
    .bdrv_read		= cloop_read,
 | 
			
		||||
    .bdrv_close		= cloop_close,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										239
									
								
								block/cow.c
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								block/cow.c
									
									
									
									
									
								
							@@ -21,9 +21,11 @@
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "module.h"
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
 | 
			
		||||
/**************************************************************/
 | 
			
		||||
/* COW block driver using file system holes */
 | 
			
		||||
@@ -42,7 +44,10 @@ struct cow_header_v2 {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVCowState {
 | 
			
		||||
    CoMutex lock;
 | 
			
		||||
    int fd;
 | 
			
		||||
    uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
 | 
			
		||||
    uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
 | 
			
		||||
    int cow_bitmap_size;
 | 
			
		||||
    int64_t cow_sectors_offset;
 | 
			
		||||
} BDRVCowState;
 | 
			
		||||
 | 
			
		||||
@@ -58,32 +63,27 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
			
		||||
        return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cow_open(BlockDriverState *bs, int flags)
 | 
			
		||||
static int cow_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCowState *s = bs->opaque;
 | 
			
		||||
    int fd;
 | 
			
		||||
    struct cow_header_v2 cow_header;
 | 
			
		||||
    int bitmap_size;
 | 
			
		||||
    int64_t size;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
 | 
			
		||||
    if (fd < 0) {
 | 
			
		||||
        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
 | 
			
		||||
        if (fd < 0)
 | 
			
		||||
            return -1;
 | 
			
		||||
    }
 | 
			
		||||
    s->fd = fd;
 | 
			
		||||
    /* see if it is a cow image */
 | 
			
		||||
    ret = bdrv_pread(bs->file, 0, &cow_header, sizeof(cow_header));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (be32_to_cpu(cow_header.magic) != COW_MAGIC) {
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (be32_to_cpu(cow_header.version) != COW_VERSION) {
 | 
			
		||||
        char version[64];
 | 
			
		||||
        snprintf(version, sizeof(version),
 | 
			
		||||
               "COW version %d", cow_header.version);
 | 
			
		||||
        qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
 | 
			
		||||
            bs->device_name, "cow", version);
 | 
			
		||||
        ret = -ENOTSUP;
 | 
			
		||||
    if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
 | 
			
		||||
        be32_to_cpu(cow_header.version) != COW_VERSION) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -94,115 +94,81 @@ static int cow_open(BlockDriverState *bs, int flags)
 | 
			
		||||
    pstrcpy(bs->backing_file, sizeof(bs->backing_file),
 | 
			
		||||
            cow_header.backing_file);
 | 
			
		||||
 | 
			
		||||
    bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
 | 
			
		||||
    s->cow_sectors_offset = (bitmap_size + 511) & ~511;
 | 
			
		||||
    qemu_co_mutex_init(&s->lock);
 | 
			
		||||
    /* mmap the bitmap */
 | 
			
		||||
    s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
 | 
			
		||||
    s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size),
 | 
			
		||||
                                      s->cow_bitmap_size,
 | 
			
		||||
                                      PROT_READ | PROT_WRITE,
 | 
			
		||||
                                      MAP_SHARED, s->fd, 0);
 | 
			
		||||
    if (s->cow_bitmap_addr == MAP_FAILED)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
 | 
			
		||||
    s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
 | 
			
		||||
    return 0;
 | 
			
		||||
 fail:
 | 
			
		||||
    return ret;
 | 
			
		||||
    close(fd);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * XXX(hch): right now these functions are extremely inefficient.
 | 
			
		||||
 * We should just read the whole bitmap we'll need in one go instead.
 | 
			
		||||
 */
 | 
			
		||||
static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
 | 
			
		||||
static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
 | 
			
		||||
    uint8_t bitmap;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
       return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bitmap |= (1 << (bitnum % 8));
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pwrite_sync(bs->file, offset, &bitmap, sizeof(bitmap));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
       return ret;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
    bitmap[bitnum / 8] |= (1 << (bitnum%8));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum)
 | 
			
		||||
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
 | 
			
		||||
    uint8_t bitmap;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
       return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return !!(bitmap & (1 << (bitnum % 8)));
 | 
			
		||||
    return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Return true if first block has been changed (ie. current version is
 | 
			
		||||
 * in COW file).  Set the number of continuous blocks for which that
 | 
			
		||||
 * is true. */
 | 
			
		||||
static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, int nb_sectors, int *num_same)
 | 
			
		||||
static inline int is_changed(uint8_t *bitmap,
 | 
			
		||||
                             int64_t sector_num, int nb_sectors,
 | 
			
		||||
                             int *num_same)
 | 
			
		||||
{
 | 
			
		||||
    int changed;
 | 
			
		||||
 | 
			
		||||
    if (nb_sectors == 0) {
 | 
			
		||||
    if (!bitmap || nb_sectors == 0) {
 | 
			
		||||
	*num_same = nb_sectors;
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    changed = is_bit_set(bs, sector_num);
 | 
			
		||||
    if (changed < 0) {
 | 
			
		||||
        return 0; /* XXX: how to return I/O errors? */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    changed = is_bit_set(bitmap, sector_num);
 | 
			
		||||
    for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
 | 
			
		||||
	if (is_bit_set(bs, sector_num + *num_same) != changed)
 | 
			
		||||
	if (is_bit_set(bitmap, sector_num + *num_same) != changed)
 | 
			
		||||
	    break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return changed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
        int nb_sectors)
 | 
			
		||||
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                            int nb_sectors, int *pnum)
 | 
			
		||||
{
 | 
			
		||||
    int error = 0;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < nb_sectors; i++) {
 | 
			
		||||
        error = cow_set_bit(bs, sector_num + i);
 | 
			
		||||
        if (error) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return error;
 | 
			
		||||
    BDRVCowState *s = bs->opaque;
 | 
			
		||||
    return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
static int cow_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                    uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCowState *s = bs->opaque;
 | 
			
		||||
    int ret, n;
 | 
			
		||||
 | 
			
		||||
    while (nb_sectors > 0) {
 | 
			
		||||
        if (bdrv_co_is_allocated(bs, sector_num, nb_sectors, &n)) {
 | 
			
		||||
            ret = bdrv_pread(bs->file,
 | 
			
		||||
                        s->cow_sectors_offset + sector_num * 512,
 | 
			
		||||
                        buf, n * 512);
 | 
			
		||||
            if (ret < 0) {
 | 
			
		||||
                return ret;
 | 
			
		||||
            }
 | 
			
		||||
        if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
 | 
			
		||||
            lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
 | 
			
		||||
            ret = read(s->fd, buf, n * 512);
 | 
			
		||||
            if (ret != n * 512)
 | 
			
		||||
                return -1;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (bs->backing_hd) {
 | 
			
		||||
                /* read from the base image */
 | 
			
		||||
                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
 | 
			
		||||
                if (ret < 0) {
 | 
			
		||||
                    return ret;
 | 
			
		||||
                }
 | 
			
		||||
                if (ret < 0)
 | 
			
		||||
                    return -1;
 | 
			
		||||
            } else {
 | 
			
		||||
            memset(buf, 0, n * 512);
 | 
			
		||||
        }
 | 
			
		||||
@@ -214,55 +180,35 @@ static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static coroutine_fn int cow_co_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                    uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    BDRVCowState *s = bs->opaque;
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
    ret = cow_read(bs, sector_num, buf, nb_sectors);
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cow_write(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                     const uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCowState *s = bs->opaque;
 | 
			
		||||
    int ret;
 | 
			
		||||
    int ret, i;
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512,
 | 
			
		||||
                      buf, nb_sectors * 512);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return cow_update_bitmap(bs, sector_num, nb_sectors);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static coroutine_fn int cow_co_write(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                     const uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    BDRVCowState *s = bs->opaque;
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
    ret = cow_write(bs, sector_num, buf, nb_sectors);
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
    return ret;
 | 
			
		||||
    lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
 | 
			
		||||
    ret = write(s->fd, buf, nb_sectors * 512);
 | 
			
		||||
    if (ret != nb_sectors * 512)
 | 
			
		||||
        return -1;
 | 
			
		||||
    for (i = 0; i < nb_sectors; i++)
 | 
			
		||||
        cow_set_bit(s->cow_bitmap, sector_num + i);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cow_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCowState *s = bs->opaque;
 | 
			
		||||
    munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size);
 | 
			
		||||
    close(s->fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cow_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
{
 | 
			
		||||
    int fd, cow_fd;
 | 
			
		||||
    struct cow_header_v2 cow_header;
 | 
			
		||||
    struct stat st;
 | 
			
		||||
    int64_t image_sectors = 0;
 | 
			
		||||
    const char *image_filename = NULL;
 | 
			
		||||
    int ret;
 | 
			
		||||
    BlockDriverState *cow_bs;
 | 
			
		||||
 | 
			
		||||
    /* Read out options */
 | 
			
		||||
    while (options && options->name) {
 | 
			
		||||
@@ -274,16 +220,10 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
        options++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_create_file(filename, options);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_file_open(&cow_bs, filename, BDRV_O_RDWR);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
 | 
			
		||||
              0644);
 | 
			
		||||
    if (cow_fd < 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
    memset(&cow_header, 0, sizeof(cow_header));
 | 
			
		||||
    cow_header.magic = cpu_to_be32(COW_MAGIC);
 | 
			
		||||
    cow_header.version = cpu_to_be32(COW_VERSION);
 | 
			
		||||
@@ -291,9 +231,16 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
        /* Note: if no file, we put a dummy mtime */
 | 
			
		||||
        cow_header.mtime = cpu_to_be32(0);
 | 
			
		||||
 | 
			
		||||
        if (stat(image_filename, &st) != 0) {
 | 
			
		||||
        fd = open(image_filename, O_RDONLY | O_BINARY);
 | 
			
		||||
        if (fd < 0) {
 | 
			
		||||
            close(cow_fd);
 | 
			
		||||
            goto mtime_fail;
 | 
			
		||||
        }
 | 
			
		||||
        if (fstat(fd, &st) != 0) {
 | 
			
		||||
            close(fd);
 | 
			
		||||
            goto mtime_fail;
 | 
			
		||||
        }
 | 
			
		||||
        close(fd);
 | 
			
		||||
        cow_header.mtime = cpu_to_be32(st.st_mtime);
 | 
			
		||||
    mtime_fail:
 | 
			
		||||
        pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
 | 
			
		||||
@@ -301,21 +248,17 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
    }
 | 
			
		||||
    cow_header.sectorsize = cpu_to_be32(512);
 | 
			
		||||
    cow_header.size = cpu_to_be64(image_sectors * 512);
 | 
			
		||||
    ret = bdrv_pwrite(cow_bs, 0, &cow_header, sizeof(cow_header));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto exit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    write(cow_fd, &cow_header, sizeof(cow_header));
 | 
			
		||||
    /* resize to include at least all the bitmap */
 | 
			
		||||
    ret = bdrv_truncate(cow_bs,
 | 
			
		||||
        sizeof(cow_header) + ((image_sectors + 7) >> 3));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto exit;
 | 
			
		||||
    }
 | 
			
		||||
    ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
 | 
			
		||||
    close(cow_fd);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
exit:
 | 
			
		||||
    bdrv_delete(cow_bs);
 | 
			
		||||
    return ret;
 | 
			
		||||
static void cow_flush(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCowState *s = bs->opaque;
 | 
			
		||||
    qemu_fdatasync(s->fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QEMUOptionParameter cow_create_options[] = {
 | 
			
		||||
@@ -335,15 +278,14 @@ static QEMUOptionParameter cow_create_options[] = {
 | 
			
		||||
static BlockDriver bdrv_cow = {
 | 
			
		||||
    .format_name	= "cow",
 | 
			
		||||
    .instance_size	= sizeof(BDRVCowState),
 | 
			
		||||
 | 
			
		||||
    .bdrv_probe		= cow_probe,
 | 
			
		||||
    .bdrv_open		= cow_open,
 | 
			
		||||
    .bdrv_read		= cow_read,
 | 
			
		||||
    .bdrv_write		= cow_write,
 | 
			
		||||
    .bdrv_close		= cow_close,
 | 
			
		||||
    .bdrv_create	= cow_create,
 | 
			
		||||
 | 
			
		||||
    .bdrv_read              = cow_co_read,
 | 
			
		||||
    .bdrv_write             = cow_co_write,
 | 
			
		||||
    .bdrv_co_is_allocated   = cow_co_is_allocated,
 | 
			
		||||
    .bdrv_flush		= cow_flush,
 | 
			
		||||
    .bdrv_is_allocated	= cow_is_allocated,
 | 
			
		||||
 | 
			
		||||
    .create_options = cow_create_options,
 | 
			
		||||
};
 | 
			
		||||
@@ -354,3 +296,4 @@ static void bdrv_cow_init(void)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
block_init(bdrv_cow_init);
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										154
									
								
								block/curl.c
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								block/curl.c
									
									
									
									
									
								
							@@ -29,9 +29,9 @@
 | 
			
		||||
// #define DEBUG_VERBOSE
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_CURL
 | 
			
		||||
#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
 | 
			
		||||
#define dprintf(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
 | 
			
		||||
#else
 | 
			
		||||
#define DPRINTF(fmt, ...) do { } while (0)
 | 
			
		||||
#define dprintf(fmt, ...) do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define CURL_NUM_STATES 8
 | 
			
		||||
@@ -47,12 +47,7 @@ struct BDRVCURLState;
 | 
			
		||||
 | 
			
		||||
typedef struct CURLAIOCB {
 | 
			
		||||
    BlockDriverAIOCB common;
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
    QEMUIOVector *qiov;
 | 
			
		||||
 | 
			
		||||
    int64_t sector_num;
 | 
			
		||||
    int nb_sectors;
 | 
			
		||||
 | 
			
		||||
    size_t start;
 | 
			
		||||
    size_t end;
 | 
			
		||||
} CURLAIOCB;
 | 
			
		||||
@@ -81,25 +76,24 @@ typedef struct BDRVCURLState {
 | 
			
		||||
 | 
			
		||||
static void curl_clean_state(CURLState *s);
 | 
			
		||||
static void curl_multi_do(void *arg);
 | 
			
		||||
static int curl_aio_flush(void *opaque);
 | 
			
		||||
 | 
			
		||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
 | 
			
		||||
                        void *s, void *sp)
 | 
			
		||||
{
 | 
			
		||||
    DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
 | 
			
		||||
    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_do, NULL, curl_aio_flush, s);
 | 
			
		||||
            qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, NULL, NULL, s);
 | 
			
		||||
            break;
 | 
			
		||||
        case CURL_POLL_OUT:
 | 
			
		||||
            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush, s);
 | 
			
		||||
            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, NULL, NULL, s);
 | 
			
		||||
            break;
 | 
			
		||||
        case CURL_POLL_INOUT:
 | 
			
		||||
            qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
 | 
			
		||||
                                    curl_aio_flush, s);
 | 
			
		||||
            qemu_aio_set_fd_handler(fd, curl_multi_do,
 | 
			
		||||
                                    curl_multi_do, NULL, NULL, s);
 | 
			
		||||
            break;
 | 
			
		||||
        case CURL_POLL_REMOVE:
 | 
			
		||||
            qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL);
 | 
			
		||||
            qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -110,11 +104,10 @@ static size_t curl_size_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    CURLState *s = ((CURLState*)opaque);
 | 
			
		||||
    size_t realsize = size * nmemb;
 | 
			
		||||
    size_t fsize;
 | 
			
		||||
    long long fsize;
 | 
			
		||||
 | 
			
		||||
    if(sscanf(ptr, "Content-Length: %zd", &fsize) == 1) {
 | 
			
		||||
    if(sscanf(ptr, "Content-Length: %lld", &fsize) == 1)
 | 
			
		||||
        s->s->len = fsize;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return realsize;
 | 
			
		||||
}
 | 
			
		||||
@@ -125,7 +118,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
 | 
			
		||||
    size_t realsize = size * nmemb;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    DPRINTF("CURL: Just reading %zd bytes\n", realsize);
 | 
			
		||||
    dprintf("CURL: Just reading %lld bytes\n", (unsigned long long)realsize);
 | 
			
		||||
 | 
			
		||||
    if (!s || !s->orig_buf)
 | 
			
		||||
        goto read_end;
 | 
			
		||||
@@ -235,23 +228,6 @@ static void curl_multi_do(void *arg)
 | 
			
		||||
            {
 | 
			
		||||
                CURLState *state = NULL;
 | 
			
		||||
                curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
 | 
			
		||||
 | 
			
		||||
                /* ACBs for successful messages get completed in curl_read_cb */
 | 
			
		||||
                if (msg->data.result != CURLE_OK) {
 | 
			
		||||
                    int i;
 | 
			
		||||
                    for (i = 0; i < CURL_NUM_ACB; i++) {
 | 
			
		||||
                        CURLAIOCB *acb = state->acb[i];
 | 
			
		||||
 | 
			
		||||
                        if (acb == NULL) {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        acb->common.cb(acb->common.opaque, -EIO);
 | 
			
		||||
                        qemu_aio_release(acb);
 | 
			
		||||
                        state->acb[i] = NULL;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                curl_clean_state(state);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
@@ -280,7 +256,7 @@ static CURLState *curl_init_state(BDRVCURLState *s)
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (!state) {
 | 
			
		||||
            g_usleep(100);
 | 
			
		||||
            usleep(100);
 | 
			
		||||
            curl_multi_do(s);
 | 
			
		||||
        }
 | 
			
		||||
    } while(!state);
 | 
			
		||||
@@ -300,7 +276,6 @@ static CURLState *curl_init_state(BDRVCURLState *s)
 | 
			
		||||
    curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
 | 
			
		||||
    curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
 | 
			
		||||
    curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
 | 
			
		||||
    curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
 | 
			
		||||
    
 | 
			
		||||
#ifdef DEBUG_VERBOSE
 | 
			
		||||
    curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
 | 
			
		||||
@@ -334,7 +309,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
 | 
			
		||||
    static int inited = 0;
 | 
			
		||||
 | 
			
		||||
    file = g_strdup(filename);
 | 
			
		||||
    file = qemu_strdup(filename);
 | 
			
		||||
    s->readahead_size = READ_AHEAD_SIZE;
 | 
			
		||||
 | 
			
		||||
    /* Parse a trailing ":readahead=#:" param, if present. */
 | 
			
		||||
@@ -364,7 +339,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((s->readahead_size & 0x1ff) != 0) {
 | 
			
		||||
        fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n",
 | 
			
		||||
        fprintf(stderr, "HTTP_READAHEAD_SIZE %Zd is not a multiple of 512\n",
 | 
			
		||||
                s->readahead_size);
 | 
			
		||||
        goto out_noclean;
 | 
			
		||||
    }
 | 
			
		||||
@@ -374,7 +349,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
        inited = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DPRINTF("CURL: Opening %s\n", file);
 | 
			
		||||
    dprintf("CURL: Opening %s\n", file);
 | 
			
		||||
    s->url = file;
 | 
			
		||||
    state = curl_init_state(s);
 | 
			
		||||
    if (!state)
 | 
			
		||||
@@ -393,7 +368,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
        s->len = (size_t)d;
 | 
			
		||||
    else if(!s->len)
 | 
			
		||||
        goto out;
 | 
			
		||||
    DPRINTF("CURL: Size = %zd\n", s->len);
 | 
			
		||||
    dprintf("CURL: Size = %lld\n", (long long)s->len);
 | 
			
		||||
 | 
			
		||||
    curl_clean_state(state);
 | 
			
		||||
    curl_easy_cleanup(state->curl);
 | 
			
		||||
@@ -414,25 +389,10 @@ out:
 | 
			
		||||
    curl_easy_cleanup(state->curl);
 | 
			
		||||
    state->curl = NULL;
 | 
			
		||||
out_noclean:
 | 
			
		||||
    g_free(file);
 | 
			
		||||
    qemu_free(file);
 | 
			
		||||
    return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int curl_aio_flush(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCURLState *s = opaque;
 | 
			
		||||
    int i, j;
 | 
			
		||||
 | 
			
		||||
    for (i=0; i < CURL_NUM_STATES; i++) {
 | 
			
		||||
        for(j=0; j < CURL_NUM_ACB; j++) {
 | 
			
		||||
            if (s->states[i].acb[j]) {
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
 | 
			
		||||
{
 | 
			
		||||
    // Do we have to implement canceling? Seems to work without...
 | 
			
		||||
@@ -443,82 +403,60 @@ static AIOPool curl_aio_pool = {
 | 
			
		||||
    .cancel             = curl_aio_cancel,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void curl_readv_bh_cb(void *p)
 | 
			
		||||
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVCURLState *s = bs->opaque;
 | 
			
		||||
    CURLAIOCB *acb;
 | 
			
		||||
    size_t start = sector_num * SECTOR_SIZE;
 | 
			
		||||
    size_t end;
 | 
			
		||||
    CURLState *state;
 | 
			
		||||
 | 
			
		||||
    CURLAIOCB *acb = p;
 | 
			
		||||
    BDRVCURLState *s = acb->common.bs->opaque;
 | 
			
		||||
    acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
 | 
			
		||||
    if (!acb)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    qemu_bh_delete(acb->bh);
 | 
			
		||||
    acb->bh = NULL;
 | 
			
		||||
 | 
			
		||||
    size_t start = acb->sector_num * SECTOR_SIZE;
 | 
			
		||||
    size_t end;
 | 
			
		||||
    acb->qiov = qiov;
 | 
			
		||||
 | 
			
		||||
    // In case we have the requested data already (e.g. read-ahead),
 | 
			
		||||
    // we can just call the callback and be done.
 | 
			
		||||
    switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
 | 
			
		||||
 | 
			
		||||
    switch (curl_find_buf(s, start, nb_sectors * SECTOR_SIZE, acb)) {
 | 
			
		||||
        case FIND_RET_OK:
 | 
			
		||||
            qemu_aio_release(acb);
 | 
			
		||||
            // fall through
 | 
			
		||||
        case FIND_RET_WAIT:
 | 
			
		||||
            return;
 | 
			
		||||
            return &acb->common;
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // No cache found, so let's start a new request
 | 
			
		||||
 | 
			
		||||
    state = curl_init_state(s);
 | 
			
		||||
    if (!state) {
 | 
			
		||||
        acb->common.cb(acb->common.opaque, -EIO);
 | 
			
		||||
        qemu_aio_release(acb);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (!state)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    acb->start = 0;
 | 
			
		||||
    acb->end = (acb->nb_sectors * SECTOR_SIZE);
 | 
			
		||||
    acb->end = (nb_sectors * SECTOR_SIZE);
 | 
			
		||||
 | 
			
		||||
    state->buf_off = 0;
 | 
			
		||||
    if (state->orig_buf)
 | 
			
		||||
        g_free(state->orig_buf);
 | 
			
		||||
        qemu_free(state->orig_buf);
 | 
			
		||||
    state->buf_start = start;
 | 
			
		||||
    state->buf_len = acb->end + s->readahead_size;
 | 
			
		||||
    end = MIN(start + state->buf_len, s->len) - 1;
 | 
			
		||||
    state->orig_buf = g_malloc(state->buf_len);
 | 
			
		||||
    state->orig_buf = qemu_malloc(state->buf_len);
 | 
			
		||||
    state->acb[0] = acb;
 | 
			
		||||
 | 
			
		||||
    snprintf(state->range, 127, "%zd-%zd", start, end);
 | 
			
		||||
    DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
 | 
			
		||||
            (acb->nb_sectors * SECTOR_SIZE), start, state->range);
 | 
			
		||||
    snprintf(state->range, 127, "%lld-%lld", (long long)start, (long long)end);
 | 
			
		||||
    dprintf("CURL (AIO): Reading %d at %lld (%s)\n", (nb_sectors * SECTOR_SIZE), start, state->range);
 | 
			
		||||
    curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
 | 
			
		||||
 | 
			
		||||
    curl_multi_add_handle(s->multi, state->curl);
 | 
			
		||||
    curl_multi_do(s);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    CURLAIOCB *acb;
 | 
			
		||||
 | 
			
		||||
    acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
 | 
			
		||||
 | 
			
		||||
    acb->qiov = qiov;
 | 
			
		||||
    acb->sector_num = sector_num;
 | 
			
		||||
    acb->nb_sectors = nb_sectors;
 | 
			
		||||
 | 
			
		||||
    acb->bh = qemu_bh_new(curl_readv_bh_cb, acb);
 | 
			
		||||
 | 
			
		||||
    if (!acb->bh) {
 | 
			
		||||
        DPRINTF("CURL: qemu_bh_new failed\n");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_bh_schedule(acb->bh);
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -527,7 +465,7 @@ static void curl_close(BlockDriverState *bs)
 | 
			
		||||
    BDRVCURLState *s = bs->opaque;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    DPRINTF("CURL: Close\n");
 | 
			
		||||
    dprintf("CURL: Close\n");
 | 
			
		||||
    for (i=0; i<CURL_NUM_STATES; i++) {
 | 
			
		||||
        if (s->states[i].in_use)
 | 
			
		||||
            curl_clean_state(&s->states[i]);
 | 
			
		||||
@@ -536,7 +474,7 @@ static void curl_close(BlockDriverState *bs)
 | 
			
		||||
            s->states[i].curl = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        if (s->states[i].orig_buf) {
 | 
			
		||||
            g_free(s->states[i].orig_buf);
 | 
			
		||||
            qemu_free(s->states[i].orig_buf);
 | 
			
		||||
            s->states[i].orig_buf = NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -557,7 +495,7 @@ static BlockDriver bdrv_http = {
 | 
			
		||||
    .protocol_name   = "http",
 | 
			
		||||
 | 
			
		||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
			
		||||
    .bdrv_file_open  = curl_open,
 | 
			
		||||
    .bdrv_open       = curl_open,
 | 
			
		||||
    .bdrv_close      = curl_close,
 | 
			
		||||
    .bdrv_getlength  = curl_getlength,
 | 
			
		||||
 | 
			
		||||
@@ -569,7 +507,7 @@ static BlockDriver bdrv_https = {
 | 
			
		||||
    .protocol_name   = "https",
 | 
			
		||||
 | 
			
		||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
			
		||||
    .bdrv_file_open  = curl_open,
 | 
			
		||||
    .bdrv_open       = curl_open,
 | 
			
		||||
    .bdrv_close      = curl_close,
 | 
			
		||||
    .bdrv_getlength  = curl_getlength,
 | 
			
		||||
 | 
			
		||||
@@ -581,7 +519,7 @@ static BlockDriver bdrv_ftp = {
 | 
			
		||||
    .protocol_name   = "ftp",
 | 
			
		||||
 | 
			
		||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
			
		||||
    .bdrv_file_open  = curl_open,
 | 
			
		||||
    .bdrv_open       = curl_open,
 | 
			
		||||
    .bdrv_close      = curl_close,
 | 
			
		||||
    .bdrv_getlength  = curl_getlength,
 | 
			
		||||
 | 
			
		||||
@@ -593,7 +531,7 @@ static BlockDriver bdrv_ftps = {
 | 
			
		||||
    .protocol_name   = "ftps",
 | 
			
		||||
 | 
			
		||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
			
		||||
    .bdrv_file_open  = curl_open,
 | 
			
		||||
    .bdrv_open       = curl_open,
 | 
			
		||||
    .bdrv_close      = curl_close,
 | 
			
		||||
    .bdrv_getlength  = curl_getlength,
 | 
			
		||||
 | 
			
		||||
@@ -605,7 +543,7 @@ static BlockDriver bdrv_tftp = {
 | 
			
		||||
    .protocol_name   = "tftp",
 | 
			
		||||
 | 
			
		||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
			
		||||
    .bdrv_file_open  = curl_open,
 | 
			
		||||
    .bdrv_open       = curl_open,
 | 
			
		||||
    .bdrv_close      = curl_close,
 | 
			
		||||
    .bdrv_getlength  = curl_getlength,
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										134
									
								
								block/dmg.c
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								block/dmg.c
									
									
									
									
									
								
							@@ -28,7 +28,8 @@
 | 
			
		||||
#include <zlib.h>
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVDMGState {
 | 
			
		||||
    CoMutex lock;
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    /* each chunk contains a certain number of sectors,
 | 
			
		||||
     * offsets[i] is the offset in the .dmg file,
 | 
			
		||||
     * lengths[i] is the length of the compressed chunk,
 | 
			
		||||
@@ -57,86 +58,79 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static off_t read_off(BlockDriverState *bs, int64_t offset)
 | 
			
		||||
static off_t read_off(int fd)
 | 
			
		||||
{
 | 
			
		||||
	uint64_t buffer;
 | 
			
		||||
	if (bdrv_pread(bs->file, offset, &buffer, 8) < 8)
 | 
			
		||||
	if(read(fd,&buffer,8)<8)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return be64_to_cpu(buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static off_t read_uint32(BlockDriverState *bs, int64_t offset)
 | 
			
		||||
static off_t read_uint32(int fd)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t buffer;
 | 
			
		||||
	if (bdrv_pread(bs->file, offset, &buffer, 4) < 4)
 | 
			
		||||
	if(read(fd,&buffer,4)<4)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return be32_to_cpu(buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dmg_open(BlockDriverState *bs, int flags)
 | 
			
		||||
static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVDMGState *s = bs->opaque;
 | 
			
		||||
    off_t info_begin,info_end,last_in_offset,last_out_offset;
 | 
			
		||||
    uint32_t count;
 | 
			
		||||
    uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
 | 
			
		||||
    int64_t offset;
 | 
			
		||||
 | 
			
		||||
    s->fd = open(filename, O_RDONLY | O_BINARY);
 | 
			
		||||
    if (s->fd < 0)
 | 
			
		||||
        return -errno;
 | 
			
		||||
    bs->read_only = 1;
 | 
			
		||||
    s->n_chunks = 0;
 | 
			
		||||
    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
 | 
			
		||||
 | 
			
		||||
    /* read offset of info blocks */
 | 
			
		||||
    offset = bdrv_getlength(bs->file);
 | 
			
		||||
    if (offset < 0) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    offset -= 0x1d8;
 | 
			
		||||
 | 
			
		||||
    info_begin = read_off(bs, offset);
 | 
			
		||||
    if (info_begin == 0) {
 | 
			
		||||
    if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (read_uint32(bs, info_begin) != 0x100) {
 | 
			
		||||
    info_begin=read_off(s->fd);
 | 
			
		||||
    if(info_begin==0)
 | 
			
		||||
	goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    count = read_uint32(bs, info_begin + 4);
 | 
			
		||||
    if (count == 0) {
 | 
			
		||||
    if(lseek(s->fd,info_begin,SEEK_SET)<0)
 | 
			
		||||
	goto fail;
 | 
			
		||||
    if(read_uint32(s->fd)!=0x100)
 | 
			
		||||
	goto fail;
 | 
			
		||||
    if((count = read_uint32(s->fd))==0)
 | 
			
		||||
	goto fail;
 | 
			
		||||
    info_end = info_begin+count;
 | 
			
		||||
    if(lseek(s->fd,0xf8,SEEK_CUR)<0)
 | 
			
		||||
	goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    info_end = info_begin + count;
 | 
			
		||||
 | 
			
		||||
    offset = info_begin + 0x100;
 | 
			
		||||
 | 
			
		||||
    /* read offsets */
 | 
			
		||||
    last_in_offset = last_out_offset = 0;
 | 
			
		||||
    while (offset < info_end) {
 | 
			
		||||
    while(lseek(s->fd,0,SEEK_CUR)<info_end) {
 | 
			
		||||
        uint32_t type;
 | 
			
		||||
 | 
			
		||||
	count = read_uint32(bs, offset);
 | 
			
		||||
	count = read_uint32(s->fd);
 | 
			
		||||
	if(count==0)
 | 
			
		||||
	    goto fail;
 | 
			
		||||
        offset += 4;
 | 
			
		||||
 | 
			
		||||
	type = read_uint32(bs, offset);
 | 
			
		||||
	if (type == 0x6d697368 && count >= 244) {
 | 
			
		||||
	type = read_uint32(s->fd);
 | 
			
		||||
	if(type!=0x6d697368 || count<244)
 | 
			
		||||
	    lseek(s->fd,count-4,SEEK_CUR);
 | 
			
		||||
	else {
 | 
			
		||||
	    int new_size, chunk_count;
 | 
			
		||||
 | 
			
		||||
            offset += 4;
 | 
			
		||||
            offset += 200;
 | 
			
		||||
 | 
			
		||||
	    if(lseek(s->fd,200,SEEK_CUR)<0)
 | 
			
		||||
	        goto fail;
 | 
			
		||||
	    chunk_count = (count-204)/40;
 | 
			
		||||
	    new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
 | 
			
		||||
	    s->types = g_realloc(s->types, new_size/2);
 | 
			
		||||
	    s->offsets = g_realloc(s->offsets, new_size);
 | 
			
		||||
	    s->lengths = g_realloc(s->lengths, new_size);
 | 
			
		||||
	    s->sectors = g_realloc(s->sectors, new_size);
 | 
			
		||||
	    s->sectorcounts = g_realloc(s->sectorcounts, new_size);
 | 
			
		||||
	    s->types = qemu_realloc(s->types, new_size/2);
 | 
			
		||||
	    s->offsets = qemu_realloc(s->offsets, new_size);
 | 
			
		||||
	    s->lengths = qemu_realloc(s->lengths, new_size);
 | 
			
		||||
	    s->sectors = qemu_realloc(s->sectors, new_size);
 | 
			
		||||
	    s->sectorcounts = qemu_realloc(s->sectorcounts, new_size);
 | 
			
		||||
 | 
			
		||||
	    for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
 | 
			
		||||
		s->types[i] = read_uint32(bs, offset);
 | 
			
		||||
		offset += 4;
 | 
			
		||||
		s->types[i] = read_uint32(s->fd);
 | 
			
		||||
		if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
 | 
			
		||||
		    if(s->types[i]==0xffffffff) {
 | 
			
		||||
			last_in_offset = s->offsets[i-1]+s->lengths[i-1];
 | 
			
		||||
@@ -144,23 +138,15 @@ static int dmg_open(BlockDriverState *bs, int flags)
 | 
			
		||||
		    }
 | 
			
		||||
		    chunk_count--;
 | 
			
		||||
		    i--;
 | 
			
		||||
		    offset += 36;
 | 
			
		||||
		    if(lseek(s->fd,36,SEEK_CUR)<0)
 | 
			
		||||
			goto fail;
 | 
			
		||||
		    continue;
 | 
			
		||||
		}
 | 
			
		||||
		offset += 4;
 | 
			
		||||
 | 
			
		||||
		s->sectors[i] = last_out_offset+read_off(bs, offset);
 | 
			
		||||
		offset += 8;
 | 
			
		||||
 | 
			
		||||
		s->sectorcounts[i] = read_off(bs, offset);
 | 
			
		||||
		offset += 8;
 | 
			
		||||
 | 
			
		||||
		s->offsets[i] = last_in_offset+read_off(bs, offset);
 | 
			
		||||
		offset += 8;
 | 
			
		||||
 | 
			
		||||
		s->lengths[i] = read_off(bs, offset);
 | 
			
		||||
		offset += 8;
 | 
			
		||||
 | 
			
		||||
		read_uint32(s->fd);
 | 
			
		||||
		s->sectors[i] = last_out_offset+read_off(s->fd);
 | 
			
		||||
		s->sectorcounts[i] = read_off(s->fd);
 | 
			
		||||
		s->offsets[i] = last_in_offset+read_off(s->fd);
 | 
			
		||||
		s->lengths[i] = read_off(s->fd);
 | 
			
		||||
		if(s->lengths[i]>max_compressed_size)
 | 
			
		||||
		    max_compressed_size = s->lengths[i];
 | 
			
		||||
		if(s->sectorcounts[i]>max_sectors_per_chunk)
 | 
			
		||||
@@ -171,16 +157,16 @@ static int dmg_open(BlockDriverState *bs, int flags)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* initialize zlib engine */
 | 
			
		||||
    s->compressed_chunk = g_malloc(max_compressed_size+1);
 | 
			
		||||
    s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
 | 
			
		||||
    s->compressed_chunk = qemu_malloc(max_compressed_size+1);
 | 
			
		||||
    s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
 | 
			
		||||
    if(inflateInit(&s->zstream) != Z_OK)
 | 
			
		||||
	goto fail;
 | 
			
		||||
 | 
			
		||||
    s->current_chunk = s->n_chunks;
 | 
			
		||||
 | 
			
		||||
    qemu_co_mutex_init(&s->lock);
 | 
			
		||||
    return 0;
 | 
			
		||||
fail:
 | 
			
		||||
    close(s->fd);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -210,10 +196,8 @@ static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
 | 
			
		||||
    return s->n_chunks; /* error */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
 | 
			
		||||
static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
 | 
			
		||||
{
 | 
			
		||||
    BDRVDMGState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
 | 
			
		||||
	int ret;
 | 
			
		||||
	uint32_t chunk = search_chunk(s,sector_num);
 | 
			
		||||
@@ -226,12 +210,15 @@ static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
 | 
			
		||||
	case 0x80000005: { /* zlib compressed */
 | 
			
		||||
	    int i;
 | 
			
		||||
 | 
			
		||||
	    ret = lseek(s->fd, s->offsets[chunk], SEEK_SET);
 | 
			
		||||
	    if(ret<0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	    /* we need to buffer, because only the chunk as whole can be
 | 
			
		||||
	     * inflated. */
 | 
			
		||||
	    i=0;
 | 
			
		||||
	    do {
 | 
			
		||||
                ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
 | 
			
		||||
                                 s->compressed_chunk+i, s->lengths[chunk]-i);
 | 
			
		||||
		ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i);
 | 
			
		||||
		if(ret<0 && errno==EINTR)
 | 
			
		||||
		    ret=0;
 | 
			
		||||
		i+=ret;
 | 
			
		||||
@@ -252,8 +239,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
 | 
			
		||||
		return -1;
 | 
			
		||||
	    break; }
 | 
			
		||||
	case 1: /* copy */
 | 
			
		||||
	    ret = bdrv_pread(bs->file, s->offsets[chunk],
 | 
			
		||||
                             s->uncompressed_chunk, s->lengths[chunk]);
 | 
			
		||||
	    ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]);
 | 
			
		||||
	    if (ret != s->lengths[chunk])
 | 
			
		||||
		return -1;
 | 
			
		||||
	    break;
 | 
			
		||||
@@ -274,7 +260,7 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
 | 
			
		||||
    for(i=0;i<nb_sectors;i++) {
 | 
			
		||||
	uint32_t sector_offset_in_chunk;
 | 
			
		||||
	if(dmg_read_chunk(bs, sector_num+i) != 0)
 | 
			
		||||
	if(dmg_read_chunk(s, sector_num+i) != 0)
 | 
			
		||||
	    return -1;
 | 
			
		||||
	sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
 | 
			
		||||
	memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
 | 
			
		||||
@@ -282,20 +268,10 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                    uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    BDRVDMGState *s = bs->opaque;
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
    ret = dmg_read(bs, sector_num, buf, nb_sectors);
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dmg_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVDMGState *s = bs->opaque;
 | 
			
		||||
    close(s->fd);
 | 
			
		||||
    if(s->n_chunks>0) {
 | 
			
		||||
	free(s->types);
 | 
			
		||||
	free(s->offsets);
 | 
			
		||||
@@ -313,7 +289,7 @@ static BlockDriver bdrv_dmg = {
 | 
			
		||||
    .instance_size	= sizeof(BDRVDMGState),
 | 
			
		||||
    .bdrv_probe		= dmg_probe,
 | 
			
		||||
    .bdrv_open		= dmg_open,
 | 
			
		||||
    .bdrv_read          = dmg_co_read,
 | 
			
		||||
    .bdrv_read		= dmg_read,
 | 
			
		||||
    .bdrv_close		= dmg_close,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										710
									
								
								block/iscsi.c
									
									
									
									
									
								
							
							
						
						
									
										710
									
								
								block/iscsi.c
									
									
									
									
									
								
							@@ -1,710 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU Block driver for iSCSI images
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config-host.h"
 | 
			
		||||
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "qemu-error.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
 | 
			
		||||
#include <iscsi/iscsi.h>
 | 
			
		||||
#include <iscsi/scsi-lowlevel.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct IscsiLun {
 | 
			
		||||
    struct iscsi_context *iscsi;
 | 
			
		||||
    int lun;
 | 
			
		||||
    int block_size;
 | 
			
		||||
    unsigned long num_blocks;
 | 
			
		||||
} IscsiLun;
 | 
			
		||||
 | 
			
		||||
typedef struct IscsiAIOCB {
 | 
			
		||||
    BlockDriverAIOCB common;
 | 
			
		||||
    QEMUIOVector *qiov;
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
    IscsiLun *iscsilun;
 | 
			
		||||
    struct scsi_task *task;
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    int status;
 | 
			
		||||
    int canceled;
 | 
			
		||||
    size_t read_size;
 | 
			
		||||
    size_t read_offset;
 | 
			
		||||
} IscsiAIOCB;
 | 
			
		||||
 | 
			
		||||
struct IscsiTask {
 | 
			
		||||
    IscsiLun *iscsilun;
 | 
			
		||||
    BlockDriverState *bs;
 | 
			
		||||
    int status;
 | 
			
		||||
    int complete;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
 | 
			
		||||
                    void *private_data)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
 | 
			
		||||
{
 | 
			
		||||
    IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
 | 
			
		||||
    IscsiLun *iscsilun = acb->iscsilun;
 | 
			
		||||
 | 
			
		||||
    acb->common.cb(acb->common.opaque, -ECANCELED);
 | 
			
		||||
    acb->canceled = 1;
 | 
			
		||||
 | 
			
		||||
    /* send a task mgmt call to the target to cancel the task on the target */
 | 
			
		||||
    iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
 | 
			
		||||
                                     iscsi_abort_task_cb, NULL);
 | 
			
		||||
 | 
			
		||||
    /* then also cancel the task locally in libiscsi */
 | 
			
		||||
    iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static AIOPool iscsi_aio_pool = {
 | 
			
		||||
    .aiocb_size         = sizeof(IscsiAIOCB),
 | 
			
		||||
    .cancel             = iscsi_aio_cancel,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void iscsi_process_read(void *arg);
 | 
			
		||||
static void iscsi_process_write(void *arg);
 | 
			
		||||
 | 
			
		||||
static int iscsi_process_flush(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = arg;
 | 
			
		||||
 | 
			
		||||
    return iscsi_queue_length(iscsilun->iscsi) > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_set_events(IscsiLun *iscsilun)
 | 
			
		||||
{
 | 
			
		||||
    struct iscsi_context *iscsi = iscsilun->iscsi;
 | 
			
		||||
 | 
			
		||||
    qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
 | 
			
		||||
                           (iscsi_which_events(iscsi) & POLLOUT)
 | 
			
		||||
                           ? iscsi_process_write : NULL,
 | 
			
		||||
                           iscsi_process_flush, iscsilun);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_process_read(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = arg;
 | 
			
		||||
    struct iscsi_context *iscsi = iscsilun->iscsi;
 | 
			
		||||
 | 
			
		||||
    iscsi_service(iscsi, POLLIN);
 | 
			
		||||
    iscsi_set_events(iscsilun);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_process_write(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = arg;
 | 
			
		||||
    struct iscsi_context *iscsi = iscsilun->iscsi;
 | 
			
		||||
 | 
			
		||||
    iscsi_service(iscsi, POLLOUT);
 | 
			
		||||
    iscsi_set_events(iscsilun);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
 | 
			
		||||
{
 | 
			
		||||
    acb->bh = qemu_bh_new(cb, acb);
 | 
			
		||||
    if (!acb->bh) {
 | 
			
		||||
        error_report("oom: could not create iscsi bh");
 | 
			
		||||
        return -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_bh_schedule(acb->bh);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_readv_writev_bh_cb(void *p)
 | 
			
		||||
{
 | 
			
		||||
    IscsiAIOCB *acb = p;
 | 
			
		||||
 | 
			
		||||
    qemu_bh_delete(acb->bh);
 | 
			
		||||
 | 
			
		||||
    if (acb->canceled == 0) {
 | 
			
		||||
        acb->common.cb(acb->common.opaque, acb->status);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
 | 
			
		||||
                     void *command_data, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    IscsiAIOCB *acb = opaque;
 | 
			
		||||
 | 
			
		||||
    trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
 | 
			
		||||
 | 
			
		||||
    g_free(acb->buf);
 | 
			
		||||
 | 
			
		||||
    if (acb->canceled != 0) {
 | 
			
		||||
        qemu_aio_release(acb);
 | 
			
		||||
        scsi_free_scsi_task(acb->task);
 | 
			
		||||
        acb->task = NULL;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    acb->status = 0;
 | 
			
		||||
    if (status < 0) {
 | 
			
		||||
        error_report("Failed to write10 data to iSCSI lun. %s",
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        acb->status = -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
 | 
			
		||||
    scsi_free_scsi_task(acb->task);
 | 
			
		||||
    acb->task = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
 | 
			
		||||
{
 | 
			
		||||
    return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *
 | 
			
		||||
iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                 QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
                 BlockDriverCompletionFunc *cb,
 | 
			
		||||
                 void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = bs->opaque;
 | 
			
		||||
    struct iscsi_context *iscsi = iscsilun->iscsi;
 | 
			
		||||
    IscsiAIOCB *acb;
 | 
			
		||||
    size_t size;
 | 
			
		||||
    int fua = 0;
 | 
			
		||||
 | 
			
		||||
    /* set FUA on writes when cache mode is write through */
 | 
			
		||||
    if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
 | 
			
		||||
        fua = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
 | 
			
		||||
    trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
 | 
			
		||||
 | 
			
		||||
    acb->iscsilun = iscsilun;
 | 
			
		||||
    acb->qiov     = qiov;
 | 
			
		||||
 | 
			
		||||
    acb->canceled   = 0;
 | 
			
		||||
 | 
			
		||||
    /* XXX we should pass the iovec to write10 to avoid the extra copy */
 | 
			
		||||
    /* this will allow us to get rid of 'buf' completely */
 | 
			
		||||
    size = nb_sectors * BDRV_SECTOR_SIZE;
 | 
			
		||||
    acb->buf = g_malloc(size);
 | 
			
		||||
    qemu_iovec_to_buffer(acb->qiov, acb->buf);
 | 
			
		||||
    acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
 | 
			
		||||
                              sector_qemu2lun(sector_num, iscsilun),
 | 
			
		||||
                              fua, 0, iscsilun->block_size,
 | 
			
		||||
                              iscsi_aio_write10_cb, acb);
 | 
			
		||||
    if (acb->task == NULL) {
 | 
			
		||||
        error_report("iSCSI: Failed to send write10 command. %s",
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        g_free(acb->buf);
 | 
			
		||||
        qemu_aio_release(acb);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iscsi_set_events(iscsilun);
 | 
			
		||||
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
 | 
			
		||||
                    void *command_data, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    IscsiAIOCB *acb = opaque;
 | 
			
		||||
 | 
			
		||||
    trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
 | 
			
		||||
 | 
			
		||||
    if (acb->canceled != 0) {
 | 
			
		||||
        qemu_aio_release(acb);
 | 
			
		||||
        scsi_free_scsi_task(acb->task);
 | 
			
		||||
        acb->task = NULL;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    acb->status = 0;
 | 
			
		||||
    if (status != 0) {
 | 
			
		||||
        error_report("Failed to read10 data from iSCSI lun. %s",
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        acb->status = -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
 | 
			
		||||
    scsi_free_scsi_task(acb->task);
 | 
			
		||||
    acb->task = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *
 | 
			
		||||
iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
                BlockDriverCompletionFunc *cb,
 | 
			
		||||
                void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = bs->opaque;
 | 
			
		||||
    struct iscsi_context *iscsi = iscsilun->iscsi;
 | 
			
		||||
    IscsiAIOCB *acb;
 | 
			
		||||
    size_t qemu_read_size, lun_read_size;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
 | 
			
		||||
 | 
			
		||||
    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
 | 
			
		||||
    trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
 | 
			
		||||
 | 
			
		||||
    acb->iscsilun = iscsilun;
 | 
			
		||||
    acb->qiov     = qiov;
 | 
			
		||||
 | 
			
		||||
    acb->canceled    = 0;
 | 
			
		||||
    acb->read_size   = qemu_read_size;
 | 
			
		||||
    acb->buf         = NULL;
 | 
			
		||||
 | 
			
		||||
    /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
 | 
			
		||||
     * may be misaligned to the LUN, so we may need to read some extra
 | 
			
		||||
     * data.
 | 
			
		||||
     */
 | 
			
		||||
    acb->read_offset = 0;
 | 
			
		||||
    if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
 | 
			
		||||
        uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
 | 
			
		||||
 | 
			
		||||
        acb->read_offset  = bdrv_offset % iscsilun->block_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lun_read_size  = (qemu_read_size + iscsilun->block_size
 | 
			
		||||
                     + acb->read_offset - 1)
 | 
			
		||||
                     / iscsilun->block_size * iscsilun->block_size;
 | 
			
		||||
    acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
 | 
			
		||||
                             sector_qemu2lun(sector_num, iscsilun),
 | 
			
		||||
                             lun_read_size, iscsilun->block_size,
 | 
			
		||||
                             iscsi_aio_read10_cb, acb);
 | 
			
		||||
    if (acb->task == NULL) {
 | 
			
		||||
        error_report("iSCSI: Failed to send read10 command. %s",
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        qemu_aio_release(acb);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < acb->qiov->niov; i++) {
 | 
			
		||||
        scsi_task_add_data_in_buffer(acb->task,
 | 
			
		||||
                acb->qiov->iov[i].iov_len,
 | 
			
		||||
                acb->qiov->iov[i].iov_base);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iscsi_set_events(iscsilun);
 | 
			
		||||
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
 | 
			
		||||
                     void *command_data, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    IscsiAIOCB *acb = opaque;
 | 
			
		||||
 | 
			
		||||
    if (acb->canceled != 0) {
 | 
			
		||||
        qemu_aio_release(acb);
 | 
			
		||||
        scsi_free_scsi_task(acb->task);
 | 
			
		||||
        acb->task = NULL;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    acb->status = 0;
 | 
			
		||||
    if (status < 0) {
 | 
			
		||||
        error_report("Failed to sync10 data on iSCSI lun. %s",
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        acb->status = -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
 | 
			
		||||
    scsi_free_scsi_task(acb->task);
 | 
			
		||||
    acb->task = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *
 | 
			
		||||
iscsi_aio_flush(BlockDriverState *bs,
 | 
			
		||||
                BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = bs->opaque;
 | 
			
		||||
    struct iscsi_context *iscsi = iscsilun->iscsi;
 | 
			
		||||
    IscsiAIOCB *acb;
 | 
			
		||||
 | 
			
		||||
    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
 | 
			
		||||
 | 
			
		||||
    acb->iscsilun = iscsilun;
 | 
			
		||||
    acb->canceled   = 0;
 | 
			
		||||
 | 
			
		||||
    acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
 | 
			
		||||
                                         0, 0, 0, 0,
 | 
			
		||||
                                         iscsi_synccache10_cb,
 | 
			
		||||
                                         acb);
 | 
			
		||||
    if (acb->task == NULL) {
 | 
			
		||||
        error_report("iSCSI: Failed to send synchronizecache10 command. %s",
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        qemu_aio_release(acb);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iscsi_set_events(iscsilun);
 | 
			
		||||
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t
 | 
			
		||||
iscsi_getlength(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = bs->opaque;
 | 
			
		||||
    int64_t len;
 | 
			
		||||
 | 
			
		||||
    len  = iscsilun->num_blocks;
 | 
			
		||||
    len *= iscsilun->block_size;
 | 
			
		||||
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
 | 
			
		||||
                        void *command_data, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    struct IscsiTask *itask = opaque;
 | 
			
		||||
    struct scsi_readcapacity10 *rc10;
 | 
			
		||||
    struct scsi_task *task = command_data;
 | 
			
		||||
 | 
			
		||||
    if (status != 0) {
 | 
			
		||||
        error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        itask->status   = 1;
 | 
			
		||||
        itask->complete = 1;
 | 
			
		||||
        scsi_free_scsi_task(task);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rc10 = scsi_datain_unmarshall(task);
 | 
			
		||||
    if (rc10 == NULL) {
 | 
			
		||||
        error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
 | 
			
		||||
        itask->status   = 1;
 | 
			
		||||
        itask->complete = 1;
 | 
			
		||||
        scsi_free_scsi_task(task);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    itask->iscsilun->block_size = rc10->block_size;
 | 
			
		||||
    itask->iscsilun->num_blocks = rc10->lba;
 | 
			
		||||
    itask->bs->total_sectors = (uint64_t)rc10->lba *
 | 
			
		||||
                               rc10->block_size / BDRV_SECTOR_SIZE ;
 | 
			
		||||
 | 
			
		||||
    itask->status   = 0;
 | 
			
		||||
    itask->complete = 1;
 | 
			
		||||
    scsi_free_scsi_task(task);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
 | 
			
		||||
                 void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    struct IscsiTask *itask = opaque;
 | 
			
		||||
    struct scsi_task *task;
 | 
			
		||||
 | 
			
		||||
    if (status != 0) {
 | 
			
		||||
        itask->status   = 1;
 | 
			
		||||
        itask->complete = 1;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, 0, 0,
 | 
			
		||||
                                   iscsi_readcapacity10_cb, opaque);
 | 
			
		||||
    if (task == NULL) {
 | 
			
		||||
        error_report("iSCSI: failed to send readcapacity command.");
 | 
			
		||||
        itask->status   = 1;
 | 
			
		||||
        itask->complete = 1;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_chap(struct iscsi_context *iscsi, const char *target)
 | 
			
		||||
{
 | 
			
		||||
    QemuOptsList *list;
 | 
			
		||||
    QemuOpts *opts;
 | 
			
		||||
    const char *user = NULL;
 | 
			
		||||
    const char *password = NULL;
 | 
			
		||||
 | 
			
		||||
    list = qemu_find_opts("iscsi");
 | 
			
		||||
    if (!list) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    opts = qemu_opts_find(list, target);
 | 
			
		||||
    if (opts == NULL) {
 | 
			
		||||
        opts = QTAILQ_FIRST(&list->head);
 | 
			
		||||
        if (!opts) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    user = qemu_opt_get(opts, "user");
 | 
			
		||||
    if (!user) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    password = qemu_opt_get(opts, "password");
 | 
			
		||||
    if (!password) {
 | 
			
		||||
        error_report("CHAP username specified but no password was given");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iscsi_set_initiator_username_pwd(iscsi, user, password)) {
 | 
			
		||||
        error_report("Failed to set initiator username and password");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void parse_header_digest(struct iscsi_context *iscsi, const char *target)
 | 
			
		||||
{
 | 
			
		||||
    QemuOptsList *list;
 | 
			
		||||
    QemuOpts *opts;
 | 
			
		||||
    const char *digest = NULL;
 | 
			
		||||
 | 
			
		||||
    list = qemu_find_opts("iscsi");
 | 
			
		||||
    if (!list) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    opts = qemu_opts_find(list, target);
 | 
			
		||||
    if (opts == NULL) {
 | 
			
		||||
        opts = QTAILQ_FIRST(&list->head);
 | 
			
		||||
        if (!opts) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    digest = qemu_opt_get(opts, "header-digest");
 | 
			
		||||
    if (!digest) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!strcmp(digest, "CRC32C")) {
 | 
			
		||||
        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C);
 | 
			
		||||
    } else if (!strcmp(digest, "NONE")) {
 | 
			
		||||
        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE);
 | 
			
		||||
    } else if (!strcmp(digest, "CRC32C-NONE")) {
 | 
			
		||||
        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE);
 | 
			
		||||
    } else if (!strcmp(digest, "NONE-CRC32C")) {
 | 
			
		||||
        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
 | 
			
		||||
    } else {
 | 
			
		||||
        error_report("Invalid header-digest setting : %s", digest);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *parse_initiator_name(const char *target)
 | 
			
		||||
{
 | 
			
		||||
    QemuOptsList *list;
 | 
			
		||||
    QemuOpts *opts;
 | 
			
		||||
    const char *name = NULL;
 | 
			
		||||
 | 
			
		||||
    list = qemu_find_opts("iscsi");
 | 
			
		||||
    if (!list) {
 | 
			
		||||
        return g_strdup("iqn.2008-11.org.linux-kvm");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    opts = qemu_opts_find(list, target);
 | 
			
		||||
    if (opts == NULL) {
 | 
			
		||||
        opts = QTAILQ_FIRST(&list->head);
 | 
			
		||||
        if (!opts) {
 | 
			
		||||
            return g_strdup("iqn.2008-11.org.linux-kvm");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    name = qemu_opt_get(opts, "initiator-name");
 | 
			
		||||
    if (!name) {
 | 
			
		||||
        return g_strdup("iqn.2008-11.org.linux-kvm");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return g_strdup(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * We support iscsi url's on the form
 | 
			
		||||
 * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
 | 
			
		||||
 */
 | 
			
		||||
static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = bs->opaque;
 | 
			
		||||
    struct iscsi_context *iscsi = NULL;
 | 
			
		||||
    struct iscsi_url *iscsi_url = NULL;
 | 
			
		||||
    struct IscsiTask task;
 | 
			
		||||
    char *initiator_name = NULL;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if ((BDRV_SECTOR_SIZE % 512) != 0) {
 | 
			
		||||
        error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
 | 
			
		||||
                     "BDRV_SECTOR_SIZE(%lld) is not a multiple "
 | 
			
		||||
                     "of 512", BDRV_SECTOR_SIZE);
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iscsi_url = iscsi_parse_full_url(iscsi, filename);
 | 
			
		||||
    if (iscsi_url == NULL) {
 | 
			
		||||
        error_report("Failed to parse URL : %s %s", filename,
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memset(iscsilun, 0, sizeof(IscsiLun));
 | 
			
		||||
 | 
			
		||||
    initiator_name = parse_initiator_name(iscsi_url->target);
 | 
			
		||||
 | 
			
		||||
    iscsi = iscsi_create_context(initiator_name);
 | 
			
		||||
    if (iscsi == NULL) {
 | 
			
		||||
        error_report("iSCSI: Failed to create iSCSI context.");
 | 
			
		||||
        ret = -ENOMEM;
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
 | 
			
		||||
        error_report("iSCSI: Failed to set target name.");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iscsi_url->user != NULL) {
 | 
			
		||||
        ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
 | 
			
		||||
                                              iscsi_url->passwd);
 | 
			
		||||
        if (ret != 0) {
 | 
			
		||||
            error_report("Failed to set initiator username and password");
 | 
			
		||||
            ret = -EINVAL;
 | 
			
		||||
            goto failed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* check if we got CHAP username/password via the options */
 | 
			
		||||
    if (parse_chap(iscsi, iscsi_url->target) != 0) {
 | 
			
		||||
        error_report("iSCSI: Failed to set CHAP user/password");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
 | 
			
		||||
        error_report("iSCSI: Failed to set session type to normal.");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
 | 
			
		||||
 | 
			
		||||
    /* check if we got HEADER_DIGEST via the options */
 | 
			
		||||
    parse_header_digest(iscsi, iscsi_url->target);
 | 
			
		||||
 | 
			
		||||
    task.iscsilun = iscsilun;
 | 
			
		||||
    task.status = 0;
 | 
			
		||||
    task.complete = 0;
 | 
			
		||||
    task.bs = bs;
 | 
			
		||||
 | 
			
		||||
    iscsilun->iscsi = iscsi;
 | 
			
		||||
    iscsilun->lun   = iscsi_url->lun;
 | 
			
		||||
 | 
			
		||||
    if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
 | 
			
		||||
                                 iscsi_connect_cb, &task)
 | 
			
		||||
        != 0) {
 | 
			
		||||
        error_report("iSCSI: Failed to start async connect.");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (!task.complete) {
 | 
			
		||||
        iscsi_set_events(iscsilun);
 | 
			
		||||
        qemu_aio_wait();
 | 
			
		||||
    }
 | 
			
		||||
    if (task.status != 0) {
 | 
			
		||||
        error_report("iSCSI: Failed to connect to LUN : %s",
 | 
			
		||||
                     iscsi_get_error(iscsi));
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iscsi_url != NULL) {
 | 
			
		||||
        iscsi_destroy_url(iscsi_url);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
failed:
 | 
			
		||||
    if (initiator_name != NULL) {
 | 
			
		||||
        g_free(initiator_name);
 | 
			
		||||
    }
 | 
			
		||||
    if (iscsi_url != NULL) {
 | 
			
		||||
        iscsi_destroy_url(iscsi_url);
 | 
			
		||||
    }
 | 
			
		||||
    if (iscsi != NULL) {
 | 
			
		||||
        iscsi_destroy_context(iscsi);
 | 
			
		||||
    }
 | 
			
		||||
    memset(iscsilun, 0, sizeof(IscsiLun));
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void iscsi_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    IscsiLun *iscsilun = bs->opaque;
 | 
			
		||||
    struct iscsi_context *iscsi = iscsilun->iscsi;
 | 
			
		||||
 | 
			
		||||
    qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
 | 
			
		||||
    iscsi_destroy_context(iscsi);
 | 
			
		||||
    memset(iscsilun, 0, sizeof(IscsiLun));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_iscsi = {
 | 
			
		||||
    .format_name     = "iscsi",
 | 
			
		||||
    .protocol_name   = "iscsi",
 | 
			
		||||
 | 
			
		||||
    .instance_size   = sizeof(IscsiLun),
 | 
			
		||||
    .bdrv_file_open  = iscsi_open,
 | 
			
		||||
    .bdrv_close      = iscsi_close,
 | 
			
		||||
 | 
			
		||||
    .bdrv_getlength  = iscsi_getlength,
 | 
			
		||||
 | 
			
		||||
    .bdrv_aio_readv  = iscsi_aio_readv,
 | 
			
		||||
    .bdrv_aio_writev = iscsi_aio_writev,
 | 
			
		||||
    .bdrv_aio_flush  = iscsi_aio_flush,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void iscsi_block_init(void)
 | 
			
		||||
{
 | 
			
		||||
    bdrv_register(&bdrv_iscsi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
block_init(iscsi_block_init);
 | 
			
		||||
							
								
								
									
										513
									
								
								block/nbd.c
									
									
									
									
									
								
							
							
						
						
									
										513
									
								
								block/nbd.c
									
									
									
									
									
								
							@@ -28,463 +28,146 @@
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "nbd.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "module.h"
 | 
			
		||||
#include "qemu_socket.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#define EN_OPTSTR ":exportname="
 | 
			
		||||
 | 
			
		||||
/* #define DEBUG_NBD */
 | 
			
		||||
 | 
			
		||||
#if defined(DEBUG_NBD)
 | 
			
		||||
#define logout(fmt, ...) \
 | 
			
		||||
                fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
 | 
			
		||||
#else
 | 
			
		||||
#define logout(fmt, ...) ((void)0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MAX_NBD_REQUESTS	16
 | 
			
		||||
#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
 | 
			
		||||
#define INDEX_TO_HANDLE(bs, index)  ((index)  ^ ((uint64_t)(intptr_t)bs))
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVNBDState {
 | 
			
		||||
    int sock;
 | 
			
		||||
    uint32_t nbdflags;
 | 
			
		||||
    off_t size;
 | 
			
		||||
    size_t blocksize;
 | 
			
		||||
    char *export_name; /* An NBD server may export several devices */
 | 
			
		||||
 | 
			
		||||
    CoMutex send_mutex;
 | 
			
		||||
    CoMutex free_sema;
 | 
			
		||||
    Coroutine *send_coroutine;
 | 
			
		||||
    int in_flight;
 | 
			
		||||
 | 
			
		||||
    Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
 | 
			
		||||
    struct nbd_reply reply;
 | 
			
		||||
 | 
			
		||||
    /* If it begins with  '/', this is a UNIX domain socket. Otherwise,
 | 
			
		||||
     * it's a string of the form <hostname|ip4|\[ip6\]>:port
 | 
			
		||||
     */
 | 
			
		||||
    char *host_spec;
 | 
			
		||||
} BDRVNBDState;
 | 
			
		||||
 | 
			
		||||
static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    char *file;
 | 
			
		||||
    char *export_name;
 | 
			
		||||
    const char *host_spec;
 | 
			
		||||
    const char *unixpath;
 | 
			
		||||
    int err = -EINVAL;
 | 
			
		||||
 | 
			
		||||
    file = g_strdup(filename);
 | 
			
		||||
 | 
			
		||||
    export_name = strstr(file, EN_OPTSTR);
 | 
			
		||||
    if (export_name) {
 | 
			
		||||
        if (export_name[strlen(EN_OPTSTR)] == 0) {
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        export_name[0] = 0; /* truncate 'file' */
 | 
			
		||||
        export_name += strlen(EN_OPTSTR);
 | 
			
		||||
        s->export_name = g_strdup(export_name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* extract the host_spec - fail if it's not nbd:... */
 | 
			
		||||
    if (!strstart(file, "nbd:", &host_spec)) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* are we a UNIX or TCP socket? */
 | 
			
		||||
    if (strstart(host_spec, "unix:", &unixpath)) {
 | 
			
		||||
        if (unixpath[0] != '/') { /* We demand  an absolute path*/
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        s->host_spec = g_strdup(unixpath);
 | 
			
		||||
    } else {
 | 
			
		||||
        s->host_spec = g_strdup(host_spec);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    err = 0;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    g_free(file);
 | 
			
		||||
    if (err != 0) {
 | 
			
		||||
        g_free(s->export_name);
 | 
			
		||||
        g_free(s->host_spec);
 | 
			
		||||
    }
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void nbd_coroutine_start(BDRVNBDState *s, struct nbd_request *request)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    /* Poor man semaphore.  The free_sema is locked when no other request
 | 
			
		||||
     * can be accepted, and unlocked after receiving one reply.  */
 | 
			
		||||
    if (s->in_flight >= MAX_NBD_REQUESTS - 1) {
 | 
			
		||||
        qemu_co_mutex_lock(&s->free_sema);
 | 
			
		||||
        assert(s->in_flight < MAX_NBD_REQUESTS);
 | 
			
		||||
    }
 | 
			
		||||
    s->in_flight++;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < MAX_NBD_REQUESTS; i++) {
 | 
			
		||||
        if (s->recv_coroutine[i] == NULL) {
 | 
			
		||||
            s->recv_coroutine[i] = qemu_coroutine_self();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert(i < MAX_NBD_REQUESTS);
 | 
			
		||||
    request->handle = INDEX_TO_HANDLE(s, i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_have_request(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = opaque;
 | 
			
		||||
 | 
			
		||||
    return s->in_flight > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void nbd_reply_ready(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = opaque;
 | 
			
		||||
    uint64_t i;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (s->reply.handle == 0) {
 | 
			
		||||
        /* No reply already in flight.  Fetch a header.  It is possible
 | 
			
		||||
         * that another thread has done the same thing in parallel, so
 | 
			
		||||
         * the socket is not readable anymore.
 | 
			
		||||
         */
 | 
			
		||||
        ret = nbd_receive_reply(s->sock, &s->reply);
 | 
			
		||||
        if (ret == -EAGAIN) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            s->reply.handle = 0;
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* There's no need for a mutex on the receive side, because the
 | 
			
		||||
     * handler acts as a synchronization point and ensures that only
 | 
			
		||||
     * one coroutine is called until the reply finishes.  */
 | 
			
		||||
    i = HANDLE_TO_INDEX(s, s->reply.handle);
 | 
			
		||||
    if (i >= MAX_NBD_REQUESTS) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->recv_coroutine[i]) {
 | 
			
		||||
        qemu_coroutine_enter(s->recv_coroutine[i], NULL);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    for (i = 0; i < MAX_NBD_REQUESTS; i++) {
 | 
			
		||||
        if (s->recv_coroutine[i]) {
 | 
			
		||||
            qemu_coroutine_enter(s->recv_coroutine[i], NULL);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void nbd_restart_write(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = opaque;
 | 
			
		||||
    qemu_coroutine_enter(s->send_coroutine, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
 | 
			
		||||
                               struct iovec *iov, int offset)
 | 
			
		||||
{
 | 
			
		||||
    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,
 | 
			
		||||
                            nbd_have_request, s);
 | 
			
		||||
    rc = nbd_send_request(s->sock, request);
 | 
			
		||||
    if (rc >= 0 && iov) {
 | 
			
		||||
        ret = qemu_co_sendv(s->sock, iov, request->len, offset);
 | 
			
		||||
        if (ret != request->len) {
 | 
			
		||||
            return -EIO;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
 | 
			
		||||
                            nbd_have_request, s);
 | 
			
		||||
    s->send_coroutine = NULL;
 | 
			
		||||
    qemu_co_mutex_unlock(&s->send_mutex);
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void nbd_co_receive_reply(BDRVNBDState *s, struct nbd_request *request,
 | 
			
		||||
                                 struct nbd_reply *reply,
 | 
			
		||||
                                 struct iovec *iov, int offset)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    /* Wait until we're woken up by the read handler.  TODO: perhaps
 | 
			
		||||
     * peek at the next reply and avoid yielding if it's ours?  */
 | 
			
		||||
    qemu_coroutine_yield();
 | 
			
		||||
    *reply = s->reply;
 | 
			
		||||
    if (reply->handle != request->handle) {
 | 
			
		||||
        reply->error = EIO;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (iov && reply->error == 0) {
 | 
			
		||||
            ret = qemu_co_recvv(s->sock, iov, request->len, offset);
 | 
			
		||||
            if (ret != request->len) {
 | 
			
		||||
                reply->error = EIO;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Tell the read handler to read another header.  */
 | 
			
		||||
        s->reply.handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void nbd_coroutine_end(BDRVNBDState *s, struct nbd_request *request)
 | 
			
		||||
{
 | 
			
		||||
    int i = HANDLE_TO_INDEX(s, request->handle);
 | 
			
		||||
    s->recv_coroutine[i] = NULL;
 | 
			
		||||
    if (s->in_flight-- == MAX_NBD_REQUESTS) {
 | 
			
		||||
        qemu_co_mutex_unlock(&s->free_sema);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_establish_connection(BlockDriverState *bs)
 | 
			
		||||
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    const char *host;
 | 
			
		||||
    const char *unixpath;
 | 
			
		||||
    int sock;
 | 
			
		||||
    int ret;
 | 
			
		||||
    off_t size;
 | 
			
		||||
    size_t blocksize;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if ((flags & BDRV_O_CREAT))
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
 | 
			
		||||
    if (!strstart(filename, "nbd:", &host))
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
 | 
			
		||||
    if (strstart(host, "unix:", &unixpath)) {
 | 
			
		||||
 | 
			
		||||
        if (unixpath[0] != '/')
 | 
			
		||||
            return -EINVAL;
 | 
			
		||||
 | 
			
		||||
        sock = unix_socket_outgoing(unixpath);
 | 
			
		||||
 | 
			
		||||
    if (s->host_spec[0] == '/') {
 | 
			
		||||
        sock = unix_socket_outgoing(s->host_spec);
 | 
			
		||||
    } else {
 | 
			
		||||
        sock = tcp_socket_outgoing_spec(s->host_spec);
 | 
			
		||||
        uint16_t port;
 | 
			
		||||
        char *p, *r;
 | 
			
		||||
        char hostname[128];
 | 
			
		||||
 | 
			
		||||
        pstrcpy(hostname, 128, host);
 | 
			
		||||
 | 
			
		||||
        p = strchr(hostname, ':');
 | 
			
		||||
        if (p == NULL)
 | 
			
		||||
            return -EINVAL;
 | 
			
		||||
 | 
			
		||||
        *p = '\0';
 | 
			
		||||
        p++;
 | 
			
		||||
 | 
			
		||||
        port = strtol(p, &r, 0);
 | 
			
		||||
        if (r == p)
 | 
			
		||||
            return -EINVAL;
 | 
			
		||||
        sock = tcp_socket_outgoing(hostname, port);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Failed to establish connection */
 | 
			
		||||
    if (sock < 0) {
 | 
			
		||||
        logout("Failed to establish connection to NBD server\n");
 | 
			
		||||
    if (sock == -1)
 | 
			
		||||
        return -errno;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* NBD handshake */
 | 
			
		||||
    ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size,
 | 
			
		||||
                                &blocksize);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        logout("Failed to negotiate with the NBD server\n");
 | 
			
		||||
        closesocket(sock);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Now that we're connected, set the socket to be non-blocking and
 | 
			
		||||
     * kick the reply mechanism.  */
 | 
			
		||||
    socket_set_nonblock(sock);
 | 
			
		||||
    qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL,
 | 
			
		||||
                            nbd_have_request, s);
 | 
			
		||||
    ret = nbd_receive_negotiate(sock, &size, &blocksize);
 | 
			
		||||
    if (ret == -1)
 | 
			
		||||
        return -errno;
 | 
			
		||||
 | 
			
		||||
    s->sock = sock;
 | 
			
		||||
    s->size = size;
 | 
			
		||||
    s->blocksize = blocksize;
 | 
			
		||||
 | 
			
		||||
    logout("Established connection with NBD server\n");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void nbd_teardown_connection(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    struct nbd_request request;
 | 
			
		||||
 | 
			
		||||
    request.type = NBD_CMD_DISC;
 | 
			
		||||
    request.from = 0;
 | 
			
		||||
    request.len = 0;
 | 
			
		||||
    nbd_send_request(s->sock, &request);
 | 
			
		||||
 | 
			
		||||
    qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL);
 | 
			
		||||
    closesocket(s->sock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    int result;
 | 
			
		||||
 | 
			
		||||
    qemu_co_mutex_init(&s->send_mutex);
 | 
			
		||||
    qemu_co_mutex_init(&s->free_sema);
 | 
			
		||||
 | 
			
		||||
    /* Pop the config into our state object. Exit if invalid. */
 | 
			
		||||
    result = nbd_config(s, filename, flags);
 | 
			
		||||
    if (result != 0) {
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* establish TCP connection, return error if it fails
 | 
			
		||||
     * TODO: Configurable retry-until-timeout behaviour.
 | 
			
		||||
     */
 | 
			
		||||
    result = nbd_establish_connection(bs);
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                          int nb_sectors, QEMUIOVector *qiov,
 | 
			
		||||
                          int offset)
 | 
			
		||||
static int nbd_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                    uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    struct nbd_request request;
 | 
			
		||||
    struct nbd_reply reply;
 | 
			
		||||
    ssize_t ret;
 | 
			
		||||
 | 
			
		||||
    request.type = NBD_CMD_READ;
 | 
			
		||||
    request.from = sector_num * 512;
 | 
			
		||||
    request.len = nb_sectors * 512;
 | 
			
		||||
 | 
			
		||||
    nbd_coroutine_start(s, &request);
 | 
			
		||||
    ret = nbd_co_send_request(s, &request, NULL, 0);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        reply.error = -ret;
 | 
			
		||||
    } else {
 | 
			
		||||
        nbd_co_receive_reply(s, &request, &reply, qiov->iov, offset);
 | 
			
		||||
    }
 | 
			
		||||
    nbd_coroutine_end(s, &request);
 | 
			
		||||
    return -reply.error;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                           int nb_sectors, QEMUIOVector *qiov,
 | 
			
		||||
                           int offset)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    struct nbd_request request;
 | 
			
		||||
    struct nbd_reply reply;
 | 
			
		||||
    ssize_t ret;
 | 
			
		||||
 | 
			
		||||
    request.type = NBD_CMD_WRITE;
 | 
			
		||||
    if (!bdrv_enable_write_cache(bs) && (s->nbdflags & NBD_FLAG_SEND_FUA)) {
 | 
			
		||||
        request.type |= NBD_CMD_FLAG_FUA;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    request.from = sector_num * 512;
 | 
			
		||||
    request.len = nb_sectors * 512;
 | 
			
		||||
 | 
			
		||||
    nbd_coroutine_start(s, &request);
 | 
			
		||||
    ret = nbd_co_send_request(s, &request, qiov->iov, offset);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        reply.error = -ret;
 | 
			
		||||
    } else {
 | 
			
		||||
        nbd_co_receive_reply(s, &request, &reply, NULL, 0);
 | 
			
		||||
    }
 | 
			
		||||
    nbd_coroutine_end(s, &request);
 | 
			
		||||
    return -reply.error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* qemu-nbd has a limit of slightly less than 1M per request.  Try to
 | 
			
		||||
 * remain aligned to 4K. */
 | 
			
		||||
#define NBD_MAX_SECTORS 2040
 | 
			
		||||
 | 
			
		||||
static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                        int nb_sectors, QEMUIOVector *qiov)
 | 
			
		||||
{
 | 
			
		||||
    int offset = 0;
 | 
			
		||||
    int ret;
 | 
			
		||||
    while (nb_sectors > NBD_MAX_SECTORS) {
 | 
			
		||||
        ret = nbd_co_readv_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        offset += NBD_MAX_SECTORS * 512;
 | 
			
		||||
        sector_num += NBD_MAX_SECTORS;
 | 
			
		||||
        nb_sectors -= NBD_MAX_SECTORS;
 | 
			
		||||
    }
 | 
			
		||||
    return nbd_co_readv_1(bs, sector_num, nb_sectors, qiov, offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_co_writev(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                         int nb_sectors, QEMUIOVector *qiov)
 | 
			
		||||
{
 | 
			
		||||
    int offset = 0;
 | 
			
		||||
    int ret;
 | 
			
		||||
    while (nb_sectors > NBD_MAX_SECTORS) {
 | 
			
		||||
        ret = nbd_co_writev_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        offset += NBD_MAX_SECTORS * 512;
 | 
			
		||||
        sector_num += NBD_MAX_SECTORS;
 | 
			
		||||
        nb_sectors -= NBD_MAX_SECTORS;
 | 
			
		||||
    }
 | 
			
		||||
    return nbd_co_writev_1(bs, sector_num, nb_sectors, qiov, offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_co_flush(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    struct nbd_request request;
 | 
			
		||||
    struct nbd_reply reply;
 | 
			
		||||
    ssize_t ret;
 | 
			
		||||
 | 
			
		||||
    if (!(s->nbdflags & NBD_FLAG_SEND_FLUSH)) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    request.type = NBD_CMD_FLUSH;
 | 
			
		||||
    if (s->nbdflags & NBD_FLAG_SEND_FUA) {
 | 
			
		||||
        request.type |= NBD_CMD_FLAG_FUA;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    request.from = 0;
 | 
			
		||||
    request.len = 0;
 | 
			
		||||
 | 
			
		||||
    nbd_coroutine_start(s, &request);
 | 
			
		||||
    ret = nbd_co_send_request(s, &request, NULL, 0);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        reply.error = -ret;
 | 
			
		||||
    } else {
 | 
			
		||||
        nbd_co_receive_reply(s, &request, &reply, NULL, 0);
 | 
			
		||||
    }
 | 
			
		||||
    nbd_coroutine_end(s, &request);
 | 
			
		||||
    return -reply.error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                          int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    struct nbd_request request;
 | 
			
		||||
    struct nbd_reply reply;
 | 
			
		||||
    ssize_t ret;
 | 
			
		||||
 | 
			
		||||
    if (!(s->nbdflags & NBD_FLAG_SEND_TRIM)) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    request.type = NBD_CMD_TRIM;
 | 
			
		||||
    request.handle = (uint64_t)(intptr_t)bs;
 | 
			
		||||
    request.from = sector_num * 512;;
 | 
			
		||||
    request.len = nb_sectors * 512;
 | 
			
		||||
 | 
			
		||||
    nbd_coroutine_start(s, &request);
 | 
			
		||||
    ret = nbd_co_send_request(s, &request, NULL, 0);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        reply.error = -ret;
 | 
			
		||||
    } else {
 | 
			
		||||
        nbd_co_receive_reply(s, &request, &reply, NULL, 0);
 | 
			
		||||
    }
 | 
			
		||||
    nbd_coroutine_end(s, &request);
 | 
			
		||||
    if (nbd_send_request(s->sock, &request) == -1)
 | 
			
		||||
        return -errno;
 | 
			
		||||
 | 
			
		||||
    if (nbd_receive_reply(s->sock, &reply) == -1)
 | 
			
		||||
        return -errno;
 | 
			
		||||
 | 
			
		||||
    if (reply.error !=0)
 | 
			
		||||
        return -reply.error;
 | 
			
		||||
 | 
			
		||||
    if (reply.handle != request.handle)
 | 
			
		||||
        return -EIO;
 | 
			
		||||
 | 
			
		||||
    if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
 | 
			
		||||
        return -EIO;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nbd_write(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                     const uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    struct nbd_request request;
 | 
			
		||||
    struct nbd_reply reply;
 | 
			
		||||
 | 
			
		||||
    request.type = NBD_CMD_WRITE;
 | 
			
		||||
    request.handle = (uint64_t)(intptr_t)bs;
 | 
			
		||||
    request.from = sector_num * 512;;
 | 
			
		||||
    request.len = nb_sectors * 512;
 | 
			
		||||
 | 
			
		||||
    if (nbd_send_request(s->sock, &request) == -1)
 | 
			
		||||
        return -errno;
 | 
			
		||||
 | 
			
		||||
    if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
 | 
			
		||||
        return -EIO;
 | 
			
		||||
 | 
			
		||||
    if (nbd_receive_reply(s->sock, &reply) == -1)
 | 
			
		||||
        return -errno;
 | 
			
		||||
 | 
			
		||||
    if (reply.error !=0)
 | 
			
		||||
        return -reply.error;
 | 
			
		||||
 | 
			
		||||
    if (reply.handle != request.handle)
 | 
			
		||||
        return -EIO;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void nbd_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVNBDState *s = bs->opaque;
 | 
			
		||||
    g_free(s->export_name);
 | 
			
		||||
    g_free(s->host_spec);
 | 
			
		||||
    struct nbd_request request;
 | 
			
		||||
 | 
			
		||||
    nbd_teardown_connection(bs);
 | 
			
		||||
    request.type = NBD_CMD_DISC;
 | 
			
		||||
    request.handle = (uint64_t)(intptr_t)bs;
 | 
			
		||||
    request.from = 0;
 | 
			
		||||
    request.len = 0;
 | 
			
		||||
    nbd_send_request(s->sock, &request);
 | 
			
		||||
 | 
			
		||||
    close(s->sock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t nbd_getlength(BlockDriverState *bs)
 | 
			
		||||
@@ -497,12 +180,10 @@ static int64_t nbd_getlength(BlockDriverState *bs)
 | 
			
		||||
static BlockDriver bdrv_nbd = {
 | 
			
		||||
    .format_name	= "nbd",
 | 
			
		||||
    .instance_size	= sizeof(BDRVNBDState),
 | 
			
		||||
    .bdrv_file_open      = nbd_open,
 | 
			
		||||
    .bdrv_co_readv       = nbd_co_readv,
 | 
			
		||||
    .bdrv_co_writev      = nbd_co_writev,
 | 
			
		||||
    .bdrv_open		= nbd_open,
 | 
			
		||||
    .bdrv_read		= nbd_read,
 | 
			
		||||
    .bdrv_write		= nbd_write,
 | 
			
		||||
    .bdrv_close		= nbd_close,
 | 
			
		||||
    .bdrv_co_flush_to_os = nbd_co_flush,
 | 
			
		||||
    .bdrv_co_discard     = nbd_co_discard,
 | 
			
		||||
    .bdrv_getlength	= nbd_getlength,
 | 
			
		||||
    .protocol_name	= "nbd",
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -43,10 +43,10 @@ struct parallels_header {
 | 
			
		||||
    uint32_t catalog_entries;
 | 
			
		||||
    uint32_t nb_sectors;
 | 
			
		||||
    char padding[24];
 | 
			
		||||
} QEMU_PACKED;
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVParallelsState {
 | 
			
		||||
    CoMutex lock;
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    uint32_t *catalog_bitmap;
 | 
			
		||||
    int catalog_size;
 | 
			
		||||
@@ -68,15 +68,24 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parallels_open(BlockDriverState *bs, int flags)
 | 
			
		||||
static int parallels_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVParallelsState *s = bs->opaque;
 | 
			
		||||
    int i;
 | 
			
		||||
    int fd, i;
 | 
			
		||||
    struct parallels_header ph;
 | 
			
		||||
 | 
			
		||||
    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
 | 
			
		||||
    if (fd < 0) {
 | 
			
		||||
        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
 | 
			
		||||
        if (fd < 0)
 | 
			
		||||
            return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bs->read_only = 1; // no write support yet
 | 
			
		||||
 | 
			
		||||
    if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph))
 | 
			
		||||
    s->fd = fd;
 | 
			
		||||
 | 
			
		||||
    if (read(fd, &ph, sizeof(ph)) != sizeof(ph))
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
    if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
 | 
			
		||||
@@ -86,49 +95,62 @@ static int parallels_open(BlockDriverState *bs, int flags)
 | 
			
		||||
 | 
			
		||||
    bs->total_sectors = le32_to_cpu(ph.nb_sectors);
 | 
			
		||||
 | 
			
		||||
    if (lseek(s->fd, 64, SEEK_SET) != 64)
 | 
			
		||||
	goto fail;
 | 
			
		||||
 | 
			
		||||
    s->tracks = le32_to_cpu(ph.tracks);
 | 
			
		||||
 | 
			
		||||
    s->catalog_size = le32_to_cpu(ph.catalog_entries);
 | 
			
		||||
    s->catalog_bitmap = g_malloc(s->catalog_size * 4);
 | 
			
		||||
    if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) !=
 | 
			
		||||
    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
 | 
			
		||||
    if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
 | 
			
		||||
	s->catalog_size * 4)
 | 
			
		||||
	goto fail;
 | 
			
		||||
    for (i = 0; i < s->catalog_size; i++)
 | 
			
		||||
	le32_to_cpus(&s->catalog_bitmap[i]);
 | 
			
		||||
 | 
			
		||||
    qemu_co_mutex_init(&s->lock);
 | 
			
		||||
    return 0;
 | 
			
		||||
fail:
 | 
			
		||||
    if (s->catalog_bitmap)
 | 
			
		||||
	g_free(s->catalog_bitmap);
 | 
			
		||||
	qemu_free(s->catalog_bitmap);
 | 
			
		||||
    close(fd);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
 | 
			
		||||
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
 | 
			
		||||
{
 | 
			
		||||
    BDRVParallelsState *s = bs->opaque;
 | 
			
		||||
    uint32_t index, offset;
 | 
			
		||||
    uint64_t position;
 | 
			
		||||
 | 
			
		||||
    index = sector_num / s->tracks;
 | 
			
		||||
    offset = sector_num % s->tracks;
 | 
			
		||||
 | 
			
		||||
    /* not allocated */
 | 
			
		||||
    // not allocated
 | 
			
		||||
    if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
 | 
			
		||||
	return -1;
 | 
			
		||||
    return (uint64_t)(s->catalog_bitmap[index] + offset) * 512;
 | 
			
		||||
 | 
			
		||||
    position = (uint64_t)(s->catalog_bitmap[index] + offset) * 512;
 | 
			
		||||
 | 
			
		||||
//    fprintf(stderr, "sector: %llx index=%x offset=%x pointer=%x position=%x\n",
 | 
			
		||||
//	sector_num, index, offset, s->catalog_bitmap[index], position);
 | 
			
		||||
 | 
			
		||||
    if (lseek(s->fd, position, SEEK_SET) != position)
 | 
			
		||||
	return -1;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parallels_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                    uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    BDRVParallelsState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    while (nb_sectors > 0) {
 | 
			
		||||
        int64_t position = seek_to_sector(bs, sector_num);
 | 
			
		||||
        if (position >= 0) {
 | 
			
		||||
            if (bdrv_pread(bs->file, position, buf, 512) != 512)
 | 
			
		||||
	if (!seek_to_sector(bs, sector_num)) {
 | 
			
		||||
	    if (read(s->fd, buf, 512) != 512)
 | 
			
		||||
		return -1;
 | 
			
		||||
        } else {
 | 
			
		||||
	} else
 | 
			
		||||
            memset(buf, 0, 512);
 | 
			
		||||
        }
 | 
			
		||||
        nb_sectors--;
 | 
			
		||||
        sector_num++;
 | 
			
		||||
        buf += 512;
 | 
			
		||||
@@ -136,21 +158,11 @@ static int parallels_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static coroutine_fn int parallels_co_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                          uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    BDRVParallelsState *s = bs->opaque;
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
    ret = parallels_read(bs, sector_num, buf, nb_sectors);
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void parallels_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVParallelsState *s = bs->opaque;
 | 
			
		||||
    g_free(s->catalog_bitmap);
 | 
			
		||||
    qemu_free(s->catalog_bitmap);
 | 
			
		||||
    close(s->fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_parallels = {
 | 
			
		||||
@@ -158,7 +170,7 @@ static BlockDriver bdrv_parallels = {
 | 
			
		||||
    .instance_size	= sizeof(BDRVParallelsState),
 | 
			
		||||
    .bdrv_probe		= parallels_probe,
 | 
			
		||||
    .bdrv_open		= parallels_open,
 | 
			
		||||
    .bdrv_read          = parallels_co_read,
 | 
			
		||||
    .bdrv_read		= parallels_read,
 | 
			
		||||
    .bdrv_close		= parallels_close,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										652
									
								
								block/qcow.c
									
									
									
									
									
								
							
							
						
						
									
										652
									
								
								block/qcow.c
									
									
									
									
									
								
							@@ -26,7 +26,6 @@
 | 
			
		||||
#include "module.h"
 | 
			
		||||
#include <zlib.h>
 | 
			
		||||
#include "aes.h"
 | 
			
		||||
#include "migration.h"
 | 
			
		||||
 | 
			
		||||
/**************************************************************/
 | 
			
		||||
/* QEMU COW block driver with compression and encryption support */
 | 
			
		||||
@@ -55,6 +54,7 @@ typedef struct QCowHeader {
 | 
			
		||||
#define L2_CACHE_SIZE 16
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVQcowState {
 | 
			
		||||
    BlockDriverState *hd;
 | 
			
		||||
    int cluster_bits;
 | 
			
		||||
    int cluster_size;
 | 
			
		||||
    int cluster_sectors;
 | 
			
		||||
@@ -74,11 +74,9 @@ typedef struct BDRVQcowState {
 | 
			
		||||
    uint32_t crypt_method_header;
 | 
			
		||||
    AES_KEY aes_encrypt_key;
 | 
			
		||||
    AES_KEY aes_decrypt_key;
 | 
			
		||||
    CoMutex lock;
 | 
			
		||||
    Error *migration_blocker;
 | 
			
		||||
} BDRVQcowState;
 | 
			
		||||
 | 
			
		||||
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
 | 
			
		||||
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
 | 
			
		||||
 | 
			
		||||
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
@@ -92,16 +90,17 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
			
		||||
        return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow_open(BlockDriverState *bs, int flags)
 | 
			
		||||
static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int len, i, shift, ret;
 | 
			
		||||
    QCowHeader header;
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    ret = bdrv_file_open(&s->hd, filename, flags);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        return ret;
 | 
			
		||||
    if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    be32_to_cpus(&header.magic);
 | 
			
		||||
    be32_to_cpus(&header.version);
 | 
			
		||||
    be64_to_cpus(&header.backing_file_offset);
 | 
			
		||||
@@ -111,31 +110,15 @@ static int qcow_open(BlockDriverState *bs, int flags)
 | 
			
		||||
    be32_to_cpus(&header.crypt_method);
 | 
			
		||||
    be64_to_cpus(&header.l1_table_offset);
 | 
			
		||||
 | 
			
		||||
    if (header.magic != QCOW_MAGIC) {
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    if (header.version != QCOW_VERSION) {
 | 
			
		||||
        char version[64];
 | 
			
		||||
        snprintf(version, sizeof(version), "QCOW version %d", header.version);
 | 
			
		||||
        qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
 | 
			
		||||
            bs->device_name, "qcow", version);
 | 
			
		||||
        ret = -ENOTSUP;
 | 
			
		||||
    if (header.size <= 1 || header.cluster_bits < 9)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (header.size <= 1 || header.cluster_bits < 9) {
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
    if (header.crypt_method > QCOW_CRYPT_AES)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    if (header.crypt_method > QCOW_CRYPT_AES) {
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    s->crypt_method_header = header.crypt_method;
 | 
			
		||||
    if (s->crypt_method_header) {
 | 
			
		||||
    if (s->crypt_method_header)
 | 
			
		||||
        bs->encrypted = 1;
 | 
			
		||||
    }
 | 
			
		||||
    s->cluster_bits = header.cluster_bits;
 | 
			
		||||
    s->cluster_size = 1 << s->cluster_bits;
 | 
			
		||||
    s->cluster_sectors = 1 << (s->cluster_bits - 9);
 | 
			
		||||
@@ -149,52 +132,45 @@ static int qcow_open(BlockDriverState *bs, int flags)
 | 
			
		||||
    s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
 | 
			
		||||
 | 
			
		||||
    s->l1_table_offset = header.l1_table_offset;
 | 
			
		||||
    s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
 | 
			
		||||
               s->l1_size * sizeof(uint64_t));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
 | 
			
		||||
    if (!s->l1_table)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
 | 
			
		||||
        s->l1_size * sizeof(uint64_t))
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for(i = 0;i < s->l1_size; i++) {
 | 
			
		||||
        be64_to_cpus(&s->l1_table[i]);
 | 
			
		||||
    }
 | 
			
		||||
    /* alloc L2 cache */
 | 
			
		||||
    s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
 | 
			
		||||
    s->cluster_cache = g_malloc(s->cluster_size);
 | 
			
		||||
    s->cluster_data = g_malloc(s->cluster_size);
 | 
			
		||||
    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
 | 
			
		||||
    if (!s->l2_cache)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    s->cluster_cache = qemu_malloc(s->cluster_size);
 | 
			
		||||
    if (!s->cluster_cache)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    s->cluster_data = qemu_malloc(s->cluster_size);
 | 
			
		||||
    if (!s->cluster_data)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    s->cluster_cache_offset = -1;
 | 
			
		||||
 | 
			
		||||
    /* read the backing file name */
 | 
			
		||||
    if (header.backing_file_offset != 0) {
 | 
			
		||||
        len = header.backing_file_size;
 | 
			
		||||
        if (len > 1023) {
 | 
			
		||||
        if (len > 1023)
 | 
			
		||||
            len = 1023;
 | 
			
		||||
        }
 | 
			
		||||
        ret = bdrv_pread(bs->file, header.backing_file_offset,
 | 
			
		||||
                   bs->backing_file, len);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
        if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        bs->backing_file[len] = '\0';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Disable migration when qcow images are used */
 | 
			
		||||
    error_set(&s->migration_blocker,
 | 
			
		||||
              QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
 | 
			
		||||
              "qcow", bs->device_name, "live migration");
 | 
			
		||||
    migrate_add_blocker(s->migration_blocker);
 | 
			
		||||
 | 
			
		||||
    qemu_co_mutex_init(&s->lock);
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
 fail:
 | 
			
		||||
    g_free(s->l1_table);
 | 
			
		||||
    g_free(s->l2_cache);
 | 
			
		||||
    g_free(s->cluster_cache);
 | 
			
		||||
    g_free(s->cluster_data);
 | 
			
		||||
    return ret;
 | 
			
		||||
    qemu_free(s->l1_table);
 | 
			
		||||
    qemu_free(s->l2_cache);
 | 
			
		||||
    qemu_free(s->cluster_cache);
 | 
			
		||||
    qemu_free(s->cluster_data);
 | 
			
		||||
    bdrv_delete(s->hd);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow_set_key(BlockDriverState *bs, const char *key)
 | 
			
		||||
@@ -218,6 +194,24 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
 | 
			
		||||
        return -1;
 | 
			
		||||
    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
#if 0
 | 
			
		||||
    /* test */
 | 
			
		||||
    {
 | 
			
		||||
        uint8_t in[16];
 | 
			
		||||
        uint8_t out[16];
 | 
			
		||||
        uint8_t tmp[16];
 | 
			
		||||
        for(i=0;i<16;i++)
 | 
			
		||||
            in[i] = i;
 | 
			
		||||
        AES_encrypt(in, tmp, &s->aes_encrypt_key);
 | 
			
		||||
        AES_decrypt(tmp, out, &s->aes_decrypt_key);
 | 
			
		||||
        for(i = 0; i < 16; i++)
 | 
			
		||||
            printf(" %02x", tmp[i]);
 | 
			
		||||
        printf("\n");
 | 
			
		||||
        for(i = 0; i < 16; i++)
 | 
			
		||||
            printf(" %02x", out[i]);
 | 
			
		||||
        printf("\n");
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -277,13 +271,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
        if (!allocate)
 | 
			
		||||
            return 0;
 | 
			
		||||
        /* allocate a new l2 entry */
 | 
			
		||||
        l2_offset = bdrv_getlength(bs->file);
 | 
			
		||||
        l2_offset = bdrv_getlength(s->hd);
 | 
			
		||||
        /* round to cluster size */
 | 
			
		||||
        l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
 | 
			
		||||
        /* update the L1 entry */
 | 
			
		||||
        s->l1_table[l1_index] = l2_offset;
 | 
			
		||||
        tmp = cpu_to_be64(l2_offset);
 | 
			
		||||
        if (bdrv_pwrite_sync(bs->file,
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd,
 | 
			
		||||
                s->l1_table_offset + l1_index * sizeof(tmp),
 | 
			
		||||
                &tmp, sizeof(tmp)) < 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
@@ -313,11 +307,11 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
    l2_table = s->l2_cache + (min_index << s->l2_bits);
 | 
			
		||||
    if (new_l2_table) {
 | 
			
		||||
        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
 | 
			
		||||
        if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
 | 
			
		||||
                s->l2_size * sizeof(uint64_t)) < 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
 | 
			
		||||
        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
 | 
			
		||||
            s->l2_size * sizeof(uint64_t))
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -336,22 +330,22 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
            /* if the cluster is already compressed, we must
 | 
			
		||||
               decompress it in the case it is not completely
 | 
			
		||||
               overwritten */
 | 
			
		||||
            if (decompress_cluster(bs, cluster_offset) < 0)
 | 
			
		||||
            if (decompress_cluster(s, cluster_offset) < 0)
 | 
			
		||||
                return 0;
 | 
			
		||||
            cluster_offset = bdrv_getlength(bs->file);
 | 
			
		||||
            cluster_offset = bdrv_getlength(s->hd);
 | 
			
		||||
            cluster_offset = (cluster_offset + s->cluster_size - 1) &
 | 
			
		||||
                ~(s->cluster_size - 1);
 | 
			
		||||
            /* write the cluster content */
 | 
			
		||||
            if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, s->cluster_size) !=
 | 
			
		||||
            if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) !=
 | 
			
		||||
                s->cluster_size)
 | 
			
		||||
                return -1;
 | 
			
		||||
        } else {
 | 
			
		||||
            cluster_offset = bdrv_getlength(bs->file);
 | 
			
		||||
            cluster_offset = bdrv_getlength(s->hd);
 | 
			
		||||
            if (allocate == 1) {
 | 
			
		||||
                /* round to cluster size */
 | 
			
		||||
                cluster_offset = (cluster_offset + s->cluster_size - 1) &
 | 
			
		||||
                    ~(s->cluster_size - 1);
 | 
			
		||||
                bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
 | 
			
		||||
                bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
 | 
			
		||||
                /* if encrypted, we must initialize the cluster
 | 
			
		||||
                   content which won't be written */
 | 
			
		||||
                if (s->crypt_method &&
 | 
			
		||||
@@ -365,7 +359,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
                                            s->cluster_data,
 | 
			
		||||
                                            s->cluster_data + 512, 1, 1,
 | 
			
		||||
                                            &s->aes_encrypt_key);
 | 
			
		||||
                            if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
 | 
			
		||||
                            if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
 | 
			
		||||
                                            s->cluster_data, 512) != 512)
 | 
			
		||||
                                return -1;
 | 
			
		||||
                        }
 | 
			
		||||
@@ -379,23 +373,21 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
        /* update L2 table */
 | 
			
		||||
        tmp = cpu_to_be64(cluster_offset);
 | 
			
		||||
        l2_table[l2_index] = tmp;
 | 
			
		||||
        if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, l2_offset + l2_index * sizeof(tmp),
 | 
			
		||||
                &tmp, sizeof(tmp)) < 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return cluster_offset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int coroutine_fn qcow_co_is_allocated(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, int nb_sectors, int *pnum)
 | 
			
		||||
static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                             int nb_sectors, int *pnum)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int index_in_cluster, n;
 | 
			
		||||
    uint64_t cluster_offset;
 | 
			
		||||
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
    cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
    index_in_cluster = sector_num & (s->cluster_sectors - 1);
 | 
			
		||||
    n = s->cluster_sectors - index_in_cluster;
 | 
			
		||||
    if (n > nb_sectors)
 | 
			
		||||
@@ -431,9 +423,8 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
 | 
			
		||||
static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int ret, csize;
 | 
			
		||||
    uint64_t coffset;
 | 
			
		||||
 | 
			
		||||
@@ -441,7 +432,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
 | 
			
		||||
    if (s->cluster_cache_offset != coffset) {
 | 
			
		||||
        csize = cluster_offset >> (63 - s->cluster_bits);
 | 
			
		||||
        csize &= (s->cluster_size - 1);
 | 
			
		||||
        ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
 | 
			
		||||
        ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
 | 
			
		||||
        if (ret != csize)
 | 
			
		||||
            return -1;
 | 
			
		||||
        if (decompress_buffer(s->cluster_cache, s->cluster_size,
 | 
			
		||||
@@ -453,205 +444,313 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                         int nb_sectors, QEMUIOVector *qiov)
 | 
			
		||||
#if 0
 | 
			
		||||
 | 
			
		||||
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                     uint8_t *buf, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int index_in_cluster;
 | 
			
		||||
    int ret = 0, n;
 | 
			
		||||
    int ret, index_in_cluster, n;
 | 
			
		||||
    uint64_t cluster_offset;
 | 
			
		||||
    struct iovec hd_iov;
 | 
			
		||||
    QEMUIOVector hd_qiov;
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    void *orig_buf;
 | 
			
		||||
 | 
			
		||||
    if (qiov->niov > 1) {
 | 
			
		||||
        buf = orig_buf = qemu_blockalign(bs, qiov->size);
 | 
			
		||||
    } else {
 | 
			
		||||
        orig_buf = NULL;
 | 
			
		||||
        buf = (uint8_t *)qiov->iov->iov_base;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
 | 
			
		||||
    while (nb_sectors != 0) {
 | 
			
		||||
        /* prepare next request */
 | 
			
		||||
        cluster_offset = get_cluster_offset(bs, sector_num << 9,
 | 
			
		||||
                                                 0, 0, 0, 0);
 | 
			
		||||
    while (nb_sectors > 0) {
 | 
			
		||||
        cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
 | 
			
		||||
        index_in_cluster = sector_num & (s->cluster_sectors - 1);
 | 
			
		||||
        n = s->cluster_sectors - index_in_cluster;
 | 
			
		||||
        if (n > nb_sectors) {
 | 
			
		||||
        if (n > nb_sectors)
 | 
			
		||||
            n = nb_sectors;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!cluster_offset) {
 | 
			
		||||
            if (bs->backing_hd) {
 | 
			
		||||
                /* read from the base image */
 | 
			
		||||
                hd_iov.iov_base = (void *)buf;
 | 
			
		||||
                hd_iov.iov_len = n * 512;
 | 
			
		||||
                qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
 | 
			
		||||
                qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
                ret = bdrv_co_readv(bs->backing_hd, sector_num,
 | 
			
		||||
                                    n, &hd_qiov);
 | 
			
		||||
                qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
                if (ret < 0) {
 | 
			
		||||
                    goto fail;
 | 
			
		||||
                }
 | 
			
		||||
                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
 | 
			
		||||
                if (ret < 0)
 | 
			
		||||
                    return -1;
 | 
			
		||||
            } else {
 | 
			
		||||
                /* Note: in this case, no need to wait */
 | 
			
		||||
                memset(buf, 0, 512 * n);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
 | 
			
		||||
            /* add AIO support for compressed blocks ? */
 | 
			
		||||
            if (decompress_cluster(bs, cluster_offset) < 0) {
 | 
			
		||||
                goto fail;
 | 
			
		||||
            }
 | 
			
		||||
            memcpy(buf,
 | 
			
		||||
                   s->cluster_cache + index_in_cluster * 512, 512 * n);
 | 
			
		||||
            if (decompress_cluster(s, cluster_offset) < 0)
 | 
			
		||||
                return -1;
 | 
			
		||||
            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
 | 
			
		||||
        } else {
 | 
			
		||||
            if ((cluster_offset & 511) != 0) {
 | 
			
		||||
                goto fail;
 | 
			
		||||
            }
 | 
			
		||||
            hd_iov.iov_base = (void *)buf;
 | 
			
		||||
            hd_iov.iov_len = n * 512;
 | 
			
		||||
            qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
 | 
			
		||||
            qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
            ret = bdrv_co_readv(bs->file,
 | 
			
		||||
                                (cluster_offset >> 9) + index_in_cluster,
 | 
			
		||||
                                n, &hd_qiov);
 | 
			
		||||
            qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
            if (ret < 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
 | 
			
		||||
            if (ret != n * 512)
 | 
			
		||||
                return -1;
 | 
			
		||||
            if (s->crypt_method) {
 | 
			
		||||
                encrypt_sectors(s, sector_num, buf, buf,
 | 
			
		||||
                                n, 0,
 | 
			
		||||
                encrypt_sectors(s, sector_num, buf, buf, n, 0,
 | 
			
		||||
                                &s->aes_decrypt_key);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ret = 0;
 | 
			
		||||
 | 
			
		||||
        nb_sectors -= n;
 | 
			
		||||
        sector_num += n;
 | 
			
		||||
        buf += n * 512;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
typedef struct QCowAIOCB {
 | 
			
		||||
    BlockDriverAIOCB common;
 | 
			
		||||
    int64_t sector_num;
 | 
			
		||||
    QEMUIOVector *qiov;
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    void *orig_buf;
 | 
			
		||||
    int nb_sectors;
 | 
			
		||||
    int n;
 | 
			
		||||
    uint64_t cluster_offset;
 | 
			
		||||
    uint8_t *cluster_data;
 | 
			
		||||
    struct iovec hd_iov;
 | 
			
		||||
    QEMUIOVector hd_qiov;
 | 
			
		||||
    BlockDriverAIOCB *hd_aiocb;
 | 
			
		||||
} QCowAIOCB;
 | 
			
		||||
 | 
			
		||||
    if (qiov->niov > 1) {
 | 
			
		||||
        qemu_iovec_from_buffer(qiov, orig_buf, qiov->size);
 | 
			
		||||
        qemu_vfree(orig_buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    ret = -EIO;
 | 
			
		||||
    goto done;
 | 
			
		||||
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
 | 
			
		||||
{
 | 
			
		||||
    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
 | 
			
		||||
    if (acb->hd_aiocb)
 | 
			
		||||
        bdrv_aio_cancel(acb->hd_aiocb);
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                          int nb_sectors, QEMUIOVector *qiov)
 | 
			
		||||
static AIOPool qcow_aio_pool = {
 | 
			
		||||
    .aiocb_size         = sizeof(QCowAIOCB),
 | 
			
		||||
    .cancel             = qcow_aio_cancel,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
 | 
			
		||||
{
 | 
			
		||||
    QCowAIOCB *acb;
 | 
			
		||||
 | 
			
		||||
    acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
 | 
			
		||||
    if (!acb)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    acb->hd_aiocb = NULL;
 | 
			
		||||
    acb->sector_num = sector_num;
 | 
			
		||||
    acb->qiov = qiov;
 | 
			
		||||
    if (qiov->niov > 1) {
 | 
			
		||||
        acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
 | 
			
		||||
        if (is_write)
 | 
			
		||||
            qemu_iovec_to_buffer(qiov, acb->buf);
 | 
			
		||||
    } else {
 | 
			
		||||
        acb->buf = (uint8_t *)qiov->iov->iov_base;
 | 
			
		||||
    }
 | 
			
		||||
    acb->nb_sectors = nb_sectors;
 | 
			
		||||
    acb->n = 0;
 | 
			
		||||
    acb->cluster_offset = 0;
 | 
			
		||||
    return acb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qcow_aio_read_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    QCowAIOCB *acb = opaque;
 | 
			
		||||
    BlockDriverState *bs = acb->common.bs;
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int index_in_cluster;
 | 
			
		||||
 | 
			
		||||
    acb->hd_aiocb = NULL;
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        goto done;
 | 
			
		||||
 | 
			
		||||
 redo:
 | 
			
		||||
    /* post process the read buffer */
 | 
			
		||||
    if (!acb->cluster_offset) {
 | 
			
		||||
        /* nothing to do */
 | 
			
		||||
    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
 | 
			
		||||
        /* nothing to do */
 | 
			
		||||
    } else {
 | 
			
		||||
        if (s->crypt_method) {
 | 
			
		||||
            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
 | 
			
		||||
                            acb->n, 0,
 | 
			
		||||
                            &s->aes_decrypt_key);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    acb->nb_sectors -= acb->n;
 | 
			
		||||
    acb->sector_num += acb->n;
 | 
			
		||||
    acb->buf += acb->n * 512;
 | 
			
		||||
 | 
			
		||||
    if (acb->nb_sectors == 0) {
 | 
			
		||||
        /* request completed */
 | 
			
		||||
        ret = 0;
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* prepare next AIO request */
 | 
			
		||||
    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
 | 
			
		||||
                                             0, 0, 0, 0);
 | 
			
		||||
    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
 | 
			
		||||
    acb->n = s->cluster_sectors - index_in_cluster;
 | 
			
		||||
    if (acb->n > acb->nb_sectors)
 | 
			
		||||
        acb->n = acb->nb_sectors;
 | 
			
		||||
 | 
			
		||||
    if (!acb->cluster_offset) {
 | 
			
		||||
        if (bs->backing_hd) {
 | 
			
		||||
            /* read from the base image */
 | 
			
		||||
            acb->hd_iov.iov_base = (void *)acb->buf;
 | 
			
		||||
            acb->hd_iov.iov_len = acb->n * 512;
 | 
			
		||||
            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
 | 
			
		||||
            acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
 | 
			
		||||
                &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
 | 
			
		||||
            if (acb->hd_aiocb == NULL)
 | 
			
		||||
                goto done;
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Note: in this case, no need to wait */
 | 
			
		||||
            memset(acb->buf, 0, 512 * acb->n);
 | 
			
		||||
            goto redo;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
 | 
			
		||||
        /* add AIO support for compressed blocks ? */
 | 
			
		||||
        if (decompress_cluster(s, acb->cluster_offset) < 0)
 | 
			
		||||
            goto done;
 | 
			
		||||
        memcpy(acb->buf,
 | 
			
		||||
               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
 | 
			
		||||
        goto redo;
 | 
			
		||||
    } else {
 | 
			
		||||
        if ((acb->cluster_offset & 511) != 0) {
 | 
			
		||||
            ret = -EIO;
 | 
			
		||||
            goto done;
 | 
			
		||||
        }
 | 
			
		||||
        acb->hd_iov.iov_base = (void *)acb->buf;
 | 
			
		||||
        acb->hd_iov.iov_len = acb->n * 512;
 | 
			
		||||
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
 | 
			
		||||
        acb->hd_aiocb = bdrv_aio_readv(s->hd,
 | 
			
		||||
                            (acb->cluster_offset >> 9) + index_in_cluster,
 | 
			
		||||
                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
 | 
			
		||||
        if (acb->hd_aiocb == NULL)
 | 
			
		||||
            goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
    if (acb->qiov->niov > 1) {
 | 
			
		||||
        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
 | 
			
		||||
        qemu_vfree(acb->orig_buf);
 | 
			
		||||
    }
 | 
			
		||||
    acb->common.cb(acb->common.opaque, ret);
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    QCowAIOCB *acb;
 | 
			
		||||
 | 
			
		||||
    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
 | 
			
		||||
    if (!acb)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    qcow_aio_read_cb(acb, 0);
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qcow_aio_write_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    QCowAIOCB *acb = opaque;
 | 
			
		||||
    BlockDriverState *bs = acb->common.bs;
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int index_in_cluster;
 | 
			
		||||
    uint64_t cluster_offset;
 | 
			
		||||
    const uint8_t *src_buf;
 | 
			
		||||
    int ret = 0, n;
 | 
			
		||||
    uint8_t *cluster_data = NULL;
 | 
			
		||||
    struct iovec hd_iov;
 | 
			
		||||
    QEMUIOVector hd_qiov;
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    void *orig_buf;
 | 
			
		||||
 | 
			
		||||
    acb->hd_aiocb = NULL;
 | 
			
		||||
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        goto done;
 | 
			
		||||
 | 
			
		||||
    acb->nb_sectors -= acb->n;
 | 
			
		||||
    acb->sector_num += acb->n;
 | 
			
		||||
    acb->buf += acb->n * 512;
 | 
			
		||||
 | 
			
		||||
    if (acb->nb_sectors == 0) {
 | 
			
		||||
        /* request completed */
 | 
			
		||||
        ret = 0;
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
 | 
			
		||||
    acb->n = s->cluster_sectors - index_in_cluster;
 | 
			
		||||
    if (acb->n > acb->nb_sectors)
 | 
			
		||||
        acb->n = acb->nb_sectors;
 | 
			
		||||
    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
 | 
			
		||||
                                        index_in_cluster,
 | 
			
		||||
                                        index_in_cluster + acb->n);
 | 
			
		||||
    if (!cluster_offset || (cluster_offset & 511) != 0) {
 | 
			
		||||
        ret = -EIO;
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (s->crypt_method) {
 | 
			
		||||
        if (!acb->cluster_data) {
 | 
			
		||||
            acb->cluster_data = qemu_mallocz(s->cluster_size);
 | 
			
		||||
            if (!acb->cluster_data) {
 | 
			
		||||
                ret = -ENOMEM;
 | 
			
		||||
                goto done;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
 | 
			
		||||
                        acb->n, 1, &s->aes_encrypt_key);
 | 
			
		||||
        src_buf = acb->cluster_data;
 | 
			
		||||
    } else {
 | 
			
		||||
        src_buf = acb->buf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    acb->hd_iov.iov_base = (void *)src_buf;
 | 
			
		||||
    acb->hd_iov.iov_len = acb->n * 512;
 | 
			
		||||
    qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
 | 
			
		||||
    acb->hd_aiocb = bdrv_aio_writev(s->hd,
 | 
			
		||||
                                    (cluster_offset >> 9) + index_in_cluster,
 | 
			
		||||
                                    &acb->hd_qiov, acb->n,
 | 
			
		||||
                                    qcow_aio_write_cb, acb);
 | 
			
		||||
    if (acb->hd_aiocb == NULL)
 | 
			
		||||
        goto done;
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
    if (acb->qiov->niov > 1)
 | 
			
		||||
        qemu_vfree(acb->orig_buf);
 | 
			
		||||
    acb->common.cb(acb->common.opaque, ret);
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
 | 
			
		||||
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    QCowAIOCB *acb;
 | 
			
		||||
 | 
			
		||||
    s->cluster_cache_offset = -1; /* disable compressed cache */
 | 
			
		||||
 | 
			
		||||
    if (qiov->niov > 1) {
 | 
			
		||||
        buf = orig_buf = qemu_blockalign(bs, qiov->size);
 | 
			
		||||
        qemu_iovec_to_buffer(qiov, buf);
 | 
			
		||||
    } else {
 | 
			
		||||
        orig_buf = NULL;
 | 
			
		||||
        buf = (uint8_t *)qiov->iov->iov_base;
 | 
			
		||||
    }
 | 
			
		||||
    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 | 
			
		||||
    if (!acb)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
 | 
			
		||||
    while (nb_sectors != 0) {
 | 
			
		||||
 | 
			
		||||
        index_in_cluster = sector_num & (s->cluster_sectors - 1);
 | 
			
		||||
        n = s->cluster_sectors - index_in_cluster;
 | 
			
		||||
        if (n > nb_sectors) {
 | 
			
		||||
            n = nb_sectors;
 | 
			
		||||
        }
 | 
			
		||||
        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
 | 
			
		||||
                                            index_in_cluster,
 | 
			
		||||
                                            index_in_cluster + n);
 | 
			
		||||
        if (!cluster_offset || (cluster_offset & 511) != 0) {
 | 
			
		||||
            ret = -EIO;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (s->crypt_method) {
 | 
			
		||||
            if (!cluster_data) {
 | 
			
		||||
                cluster_data = g_malloc0(s->cluster_size);
 | 
			
		||||
            }
 | 
			
		||||
            encrypt_sectors(s, sector_num, cluster_data, buf,
 | 
			
		||||
                            n, 1, &s->aes_encrypt_key);
 | 
			
		||||
            src_buf = cluster_data;
 | 
			
		||||
        } else {
 | 
			
		||||
            src_buf = buf;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        hd_iov.iov_base = (void *)src_buf;
 | 
			
		||||
        hd_iov.iov_len = n * 512;
 | 
			
		||||
        qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
 | 
			
		||||
        qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
        ret = bdrv_co_writev(bs->file,
 | 
			
		||||
                             (cluster_offset >> 9) + index_in_cluster,
 | 
			
		||||
                             n, &hd_qiov);
 | 
			
		||||
        qemu_co_mutex_lock(&s->lock);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        ret = 0;
 | 
			
		||||
 | 
			
		||||
        nb_sectors -= n;
 | 
			
		||||
        sector_num += n;
 | 
			
		||||
        buf += n * 512;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_co_mutex_unlock(&s->lock);
 | 
			
		||||
 | 
			
		||||
    if (qiov->niov > 1) {
 | 
			
		||||
        qemu_vfree(orig_buf);
 | 
			
		||||
    }
 | 
			
		||||
    g_free(cluster_data);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
    qcow_aio_write_cb(acb, 0);
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qcow_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    g_free(s->l1_table);
 | 
			
		||||
    g_free(s->l2_cache);
 | 
			
		||||
    g_free(s->cluster_cache);
 | 
			
		||||
    g_free(s->cluster_data);
 | 
			
		||||
 | 
			
		||||
    migrate_del_blocker(s->migration_blocker);
 | 
			
		||||
    error_free(s->migration_blocker);
 | 
			
		||||
    qemu_free(s->l1_table);
 | 
			
		||||
    qemu_free(s->l2_cache);
 | 
			
		||||
    qemu_free(s->cluster_cache);
 | 
			
		||||
    qemu_free(s->cluster_data);
 | 
			
		||||
    bdrv_delete(s->hd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
{
 | 
			
		||||
    int header_size, backing_filename_len, l1_size, shift, i;
 | 
			
		||||
    int fd, header_size, backing_filename_len, l1_size, i, shift;
 | 
			
		||||
    QCowHeader header;
 | 
			
		||||
    uint8_t *tmp;
 | 
			
		||||
    uint64_t tmp;
 | 
			
		||||
    int64_t total_size = 0;
 | 
			
		||||
    const char *backing_file = NULL;
 | 
			
		||||
    int flags = 0;
 | 
			
		||||
    int ret;
 | 
			
		||||
    BlockDriverState *qcow_bs;
 | 
			
		||||
 | 
			
		||||
    /* Read out options */
 | 
			
		||||
    while (options && options->name) {
 | 
			
		||||
@@ -665,21 +764,9 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
        options++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_create_file(filename, options);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_file_open(&qcow_bs, filename, BDRV_O_RDWR);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_truncate(qcow_bs, 0);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto exit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
 | 
			
		||||
    if (fd < 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
    memset(&header, 0, sizeof(header));
 | 
			
		||||
    header.magic = cpu_to_be32(QCOW_MAGIC);
 | 
			
		||||
    header.version = cpu_to_be32(QCOW_VERSION);
 | 
			
		||||
@@ -715,35 +802,17 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* write all the data */
 | 
			
		||||
    ret = bdrv_pwrite(qcow_bs, 0, &header, sizeof(header));
 | 
			
		||||
    if (ret != sizeof(header)) {
 | 
			
		||||
        goto exit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    write(fd, &header, sizeof(header));
 | 
			
		||||
    if (backing_file) {
 | 
			
		||||
        ret = bdrv_pwrite(qcow_bs, sizeof(header),
 | 
			
		||||
            backing_file, backing_filename_len);
 | 
			
		||||
        if (ret != backing_filename_len) {
 | 
			
		||||
            goto exit;
 | 
			
		||||
        write(fd, backing_file, backing_filename_len);
 | 
			
		||||
    }
 | 
			
		||||
    lseek(fd, header_size, SEEK_SET);
 | 
			
		||||
    tmp = 0;
 | 
			
		||||
    for(i = 0;i < l1_size; i++) {
 | 
			
		||||
        write(fd, &tmp, sizeof(tmp));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tmp = g_malloc0(BDRV_SECTOR_SIZE);
 | 
			
		||||
    for (i = 0; i < ((sizeof(uint64_t)*l1_size + BDRV_SECTOR_SIZE - 1)/
 | 
			
		||||
        BDRV_SECTOR_SIZE); i++) {
 | 
			
		||||
        ret = bdrv_pwrite(qcow_bs, header_size +
 | 
			
		||||
            BDRV_SECTOR_SIZE*i, tmp, BDRV_SECTOR_SIZE);
 | 
			
		||||
        if (ret != BDRV_SECTOR_SIZE) {
 | 
			
		||||
            g_free(tmp);
 | 
			
		||||
            goto exit;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free(tmp);
 | 
			
		||||
    ret = 0;
 | 
			
		||||
exit:
 | 
			
		||||
    bdrv_delete(qcow_bs);
 | 
			
		||||
    return ret;
 | 
			
		||||
    close(fd);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow_make_empty(BlockDriverState *bs)
 | 
			
		||||
@@ -753,10 +822,10 @@ static int qcow_make_empty(BlockDriverState *bs)
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    memset(s->l1_table, 0, l1_length);
 | 
			
		||||
    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, s->l1_table_offset, s->l1_table,
 | 
			
		||||
            l1_length) < 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
    ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
 | 
			
		||||
    ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        return ret;
 | 
			
		||||
 | 
			
		||||
@@ -781,7 +850,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    if (nb_sectors != s->cluster_sectors)
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
 | 
			
		||||
    out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
 | 
			
		||||
    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
 | 
			
		||||
    if (!out_buf)
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    /* best compression, small window, no zlib header */
 | 
			
		||||
    memset(&strm, 0, sizeof(strm));
 | 
			
		||||
@@ -789,8 +860,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                       Z_DEFLATED, -12,
 | 
			
		||||
                       9, Z_DEFAULT_STRATEGY);
 | 
			
		||||
    if (ret != 0) {
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto fail;
 | 
			
		||||
        qemu_free(out_buf);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    strm.avail_in = s->cluster_size;
 | 
			
		||||
@@ -800,9 +871,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
 | 
			
		||||
    ret = deflate(&strm, Z_FINISH);
 | 
			
		||||
    if (ret != Z_STREAM_END && ret != Z_OK) {
 | 
			
		||||
        qemu_free(out_buf);
 | 
			
		||||
        deflateEnd(&strm);
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto fail;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    out_len = strm.next_out - out_buf;
 | 
			
		||||
 | 
			
		||||
@@ -810,29 +881,25 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
 | 
			
		||||
    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
 | 
			
		||||
        /* could not compress: write normal cluster */
 | 
			
		||||
        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
 | 
			
		||||
    } else {
 | 
			
		||||
        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
 | 
			
		||||
                                            out_len, 0, 0);
 | 
			
		||||
        if (cluster_offset == 0) {
 | 
			
		||||
            ret = -EIO;
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        cluster_offset &= s->cluster_offset_mask;
 | 
			
		||||
        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            goto fail;
 | 
			
		||||
        if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
 | 
			
		||||
            qemu_free(out_buf);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = 0;
 | 
			
		||||
fail:
 | 
			
		||||
    g_free(out_buf);
 | 
			
		||||
    return ret;
 | 
			
		||||
    qemu_free(out_buf);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qcow_flush(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    bdrv_flush(s->hd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | 
			
		||||
@@ -869,13 +936,12 @@ static BlockDriver bdrv_qcow = {
 | 
			
		||||
    .bdrv_open		= qcow_open,
 | 
			
		||||
    .bdrv_close		= qcow_close,
 | 
			
		||||
    .bdrv_create	= qcow_create,
 | 
			
		||||
 | 
			
		||||
    .bdrv_co_readv          = qcow_co_readv,
 | 
			
		||||
    .bdrv_co_writev         = qcow_co_writev,
 | 
			
		||||
    .bdrv_co_is_allocated   = qcow_co_is_allocated,
 | 
			
		||||
 | 
			
		||||
    .bdrv_flush		= qcow_flush,
 | 
			
		||||
    .bdrv_is_allocated	= qcow_is_allocated,
 | 
			
		||||
    .bdrv_set_key	= qcow_set_key,
 | 
			
		||||
    .bdrv_make_empty	= qcow_make_empty,
 | 
			
		||||
    .bdrv_aio_readv	= qcow_aio_readv,
 | 
			
		||||
    .bdrv_aio_writev	= qcow_aio_writev,
 | 
			
		||||
    .bdrv_write_compressed = qcow_write_compressed,
 | 
			
		||||
    .bdrv_get_info	= qcow_get_info,
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,344 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * L2/refcount table cache for the QCOW2 format
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2010 Kevin Wolf <kwolf@redhat.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "qcow2.h"
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
 | 
			
		||||
typedef struct Qcow2CachedTable {
 | 
			
		||||
    void*   table;
 | 
			
		||||
    int64_t offset;
 | 
			
		||||
    bool    dirty;
 | 
			
		||||
    int     cache_hits;
 | 
			
		||||
    int     ref;
 | 
			
		||||
} Qcow2CachedTable;
 | 
			
		||||
 | 
			
		||||
struct Qcow2Cache {
 | 
			
		||||
    Qcow2CachedTable*       entries;
 | 
			
		||||
    struct Qcow2Cache*      depends;
 | 
			
		||||
    int                     size;
 | 
			
		||||
    bool                    depends_on_flush;
 | 
			
		||||
    bool                    writethrough;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
 | 
			
		||||
    bool writethrough)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    Qcow2Cache *c;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    c = g_malloc0(sizeof(*c));
 | 
			
		||||
    c->size = num_tables;
 | 
			
		||||
    c->entries = g_malloc0(sizeof(*c->entries) * num_tables);
 | 
			
		||||
    c->writethrough = writethrough;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < c->size; i++) {
 | 
			
		||||
        c->entries[i].table = qemu_blockalign(bs, s->cluster_size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < c->size; i++) {
 | 
			
		||||
        assert(c->entries[i].ref == 0);
 | 
			
		||||
        qemu_vfree(c->entries[i].table);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free(c->entries);
 | 
			
		||||
    g_free(c);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    ret = qcow2_cache_flush(bs, c->depends);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c->depends = NULL;
 | 
			
		||||
    c->depends_on_flush = false;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
 | 
			
		||||
    if (!c->entries[i].dirty || !c->entries[i].offset) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    trace_qcow2_cache_entry_flush(qemu_coroutine_self(),
 | 
			
		||||
                                  c == s->l2_table_cache, i);
 | 
			
		||||
 | 
			
		||||
    if (c->depends) {
 | 
			
		||||
        ret = qcow2_cache_flush_dependency(bs, c);
 | 
			
		||||
    } else if (c->depends_on_flush) {
 | 
			
		||||
        ret = bdrv_flush(bs->file);
 | 
			
		||||
        if (ret >= 0) {
 | 
			
		||||
            c->depends_on_flush = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (c == s->refcount_block_cache) {
 | 
			
		||||
        BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART);
 | 
			
		||||
    } else if (c == s->l2_table_cache) {
 | 
			
		||||
        BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table,
 | 
			
		||||
        s->cluster_size);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c->entries[i].dirty = false;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int result = 0;
 | 
			
		||||
    int ret;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    trace_qcow2_cache_flush(qemu_coroutine_self(), c == s->l2_table_cache);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < c->size; i++) {
 | 
			
		||||
        ret = qcow2_cache_entry_flush(bs, c, i);
 | 
			
		||||
        if (ret < 0 && result != -ENOSPC) {
 | 
			
		||||
            result = ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (result == 0) {
 | 
			
		||||
        ret = bdrv_flush(bs->file);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            result = ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
 | 
			
		||||
    Qcow2Cache *dependency)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (dependency->depends) {
 | 
			
		||||
        ret = qcow2_cache_flush_dependency(bs, dependency);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (c->depends && (c->depends != dependency)) {
 | 
			
		||||
        ret = qcow2_cache_flush_dependency(bs, c);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c->depends = dependency;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qcow2_cache_depends_on_flush(Qcow2Cache *c)
 | 
			
		||||
{
 | 
			
		||||
    c->depends_on_flush = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    int min_count = INT_MAX;
 | 
			
		||||
    int min_index = -1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < c->size; i++) {
 | 
			
		||||
        if (c->entries[i].ref) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (c->entries[i].cache_hits < min_count) {
 | 
			
		||||
            min_index = i;
 | 
			
		||||
            min_count = c->entries[i].cache_hits;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Give newer hits priority */
 | 
			
		||||
        /* TODO Check how to optimize the replacement strategy */
 | 
			
		||||
        c->entries[i].cache_hits /= 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (min_index == -1) {
 | 
			
		||||
        /* This can't happen in current synchronous code, but leave the check
 | 
			
		||||
         * here as a reminder for whoever starts using AIO with the cache */
 | 
			
		||||
        abort();
 | 
			
		||||
    }
 | 
			
		||||
    return min_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
 | 
			
		||||
    uint64_t offset, void **table, bool read_from_disk)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int i;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
 | 
			
		||||
                          offset, read_from_disk);
 | 
			
		||||
 | 
			
		||||
    /* Check if the table is already cached */
 | 
			
		||||
    for (i = 0; i < c->size; i++) {
 | 
			
		||||
        if (c->entries[i].offset == offset) {
 | 
			
		||||
            goto found;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* If not, write a table back and replace it */
 | 
			
		||||
    i = qcow2_cache_find_entry_to_replace(c);
 | 
			
		||||
    trace_qcow2_cache_get_replace_entry(qemu_coroutine_self(),
 | 
			
		||||
                                        c == s->l2_table_cache, i);
 | 
			
		||||
    if (i < 0) {
 | 
			
		||||
        return i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = qcow2_cache_entry_flush(bs, c, i);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    trace_qcow2_cache_get_read(qemu_coroutine_self(),
 | 
			
		||||
                               c == s->l2_table_cache, i);
 | 
			
		||||
    c->entries[i].offset = 0;
 | 
			
		||||
    if (read_from_disk) {
 | 
			
		||||
        if (c == s->l2_table_cache) {
 | 
			
		||||
            BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ret = bdrv_pread(bs->file, offset, c->entries[i].table, s->cluster_size);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Give the table some hits for the start so that it won't be replaced
 | 
			
		||||
     * immediately. The number 32 is completely arbitrary. */
 | 
			
		||||
    c->entries[i].cache_hits = 32;
 | 
			
		||||
    c->entries[i].offset = offset;
 | 
			
		||||
 | 
			
		||||
    /* And return the right table */
 | 
			
		||||
found:
 | 
			
		||||
    c->entries[i].cache_hits++;
 | 
			
		||||
    c->entries[i].ref++;
 | 
			
		||||
    *table = c->entries[i].table;
 | 
			
		||||
 | 
			
		||||
    trace_qcow2_cache_get_done(qemu_coroutine_self(),
 | 
			
		||||
                               c == s->l2_table_cache, i);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
 | 
			
		||||
    void **table)
 | 
			
		||||
{
 | 
			
		||||
    return qcow2_cache_do_get(bs, c, offset, table, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
 | 
			
		||||
    void **table)
 | 
			
		||||
{
 | 
			
		||||
    return qcow2_cache_do_get(bs, c, offset, table, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < c->size; i++) {
 | 
			
		||||
        if (c->entries[i].table == *table) {
 | 
			
		||||
            goto found;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -ENOENT;
 | 
			
		||||
 | 
			
		||||
found:
 | 
			
		||||
    c->entries[i].ref--;
 | 
			
		||||
    *table = NULL;
 | 
			
		||||
 | 
			
		||||
    assert(c->entries[i].ref >= 0);
 | 
			
		||||
 | 
			
		||||
    if (c->writethrough) {
 | 
			
		||||
        return qcow2_cache_entry_flush(bs, c, i);
 | 
			
		||||
    } else {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < c->size; i++) {
 | 
			
		||||
        if (c->entries[i].table == table) {
 | 
			
		||||
            goto found;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    abort();
 | 
			
		||||
 | 
			
		||||
found:
 | 
			
		||||
    c->entries[i].dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
 | 
			
		||||
    bool enable)
 | 
			
		||||
{
 | 
			
		||||
    bool old = c->writethrough;
 | 
			
		||||
 | 
			
		||||
    if (!old && enable) {
 | 
			
		||||
        qcow2_cache_flush(bs, c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c->writethrough = enable;
 | 
			
		||||
    return old;
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -26,7 +26,7 @@
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "block/qcow2.h"
 | 
			
		||||
 | 
			
		||||
typedef struct QEMU_PACKED QCowSnapshotHeader {
 | 
			
		||||
typedef struct __attribute__((packed)) QCowSnapshotHeader {
 | 
			
		||||
    /* header is 8 byte aligned */
 | 
			
		||||
    uint64_t l1_table_offset;
 | 
			
		||||
 | 
			
		||||
@@ -46,21 +46,16 @@ typedef struct QEMU_PACKED QCowSnapshotHeader {
 | 
			
		||||
    /* name follows  */
 | 
			
		||||
} QCowSnapshotHeader;
 | 
			
		||||
 | 
			
		||||
typedef struct QEMU_PACKED QCowSnapshotExtraData {
 | 
			
		||||
    uint64_t vm_state_size_large;
 | 
			
		||||
    uint64_t disk_size;
 | 
			
		||||
} QCowSnapshotExtraData;
 | 
			
		||||
 | 
			
		||||
void qcow2_free_snapshots(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < s->nb_snapshots; i++) {
 | 
			
		||||
        g_free(s->snapshots[i].name);
 | 
			
		||||
        g_free(s->snapshots[i].id_str);
 | 
			
		||||
        qemu_free(s->snapshots[i].name);
 | 
			
		||||
        qemu_free(s->snapshots[i].id_str);
 | 
			
		||||
    }
 | 
			
		||||
    g_free(s->snapshots);
 | 
			
		||||
    qemu_free(s->snapshots);
 | 
			
		||||
    s->snapshots = NULL;
 | 
			
		||||
    s->nb_snapshots = 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -69,12 +64,10 @@ int qcow2_read_snapshots(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    QCowSnapshotHeader h;
 | 
			
		||||
    QCowSnapshotExtraData extra;
 | 
			
		||||
    QCowSnapshot *sn;
 | 
			
		||||
    int i, id_str_size, name_size;
 | 
			
		||||
    int64_t offset;
 | 
			
		||||
    uint32_t extra_data_size;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (!s->nb_snapshots) {
 | 
			
		||||
        s->snapshots = NULL;
 | 
			
		||||
@@ -83,16 +76,11 @@ int qcow2_read_snapshots(BlockDriverState *bs)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    offset = s->snapshots_offset;
 | 
			
		||||
    s->snapshots = g_malloc0(s->nb_snapshots * sizeof(QCowSnapshot));
 | 
			
		||||
 | 
			
		||||
    s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
 | 
			
		||||
    for(i = 0; i < s->nb_snapshots; i++) {
 | 
			
		||||
        /* Read statically sized part of the snapshot header */
 | 
			
		||||
        offset = align_offset(offset, 8);
 | 
			
		||||
        ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
        if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        offset += sizeof(h);
 | 
			
		||||
        sn = s->snapshots + i;
 | 
			
		||||
        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
 | 
			
		||||
@@ -106,65 +94,37 @@ int qcow2_read_snapshots(BlockDriverState *bs)
 | 
			
		||||
        id_str_size = be16_to_cpu(h.id_str_size);
 | 
			
		||||
        name_size = be16_to_cpu(h.name_size);
 | 
			
		||||
 | 
			
		||||
        /* Read extra data */
 | 
			
		||||
        ret = bdrv_pread(bs->file, offset, &extra,
 | 
			
		||||
                         MIN(sizeof(extra), extra_data_size));
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        offset += extra_data_size;
 | 
			
		||||
 | 
			
		||||
        if (extra_data_size >= 8) {
 | 
			
		||||
            sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (extra_data_size >= 16) {
 | 
			
		||||
            sn->disk_size = be64_to_cpu(extra.disk_size);
 | 
			
		||||
        } else {
 | 
			
		||||
            sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Read snapshot ID */
 | 
			
		||||
        sn->id_str = g_malloc(id_str_size + 1);
 | 
			
		||||
        ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
        sn->id_str = qemu_malloc(id_str_size + 1);
 | 
			
		||||
        if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        offset += id_str_size;
 | 
			
		||||
        sn->id_str[id_str_size] = '\0';
 | 
			
		||||
 | 
			
		||||
        /* Read snapshot name */
 | 
			
		||||
        sn->name = g_malloc(name_size + 1);
 | 
			
		||||
        ret = bdrv_pread(bs->file, offset, sn->name, name_size);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
        sn->name = qemu_malloc(name_size + 1);
 | 
			
		||||
        if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        offset += name_size;
 | 
			
		||||
        sn->name[name_size] = '\0';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s->snapshots_size = offset - s->snapshots_offset;
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
 fail:
 | 
			
		||||
    qcow2_free_snapshots(bs);
 | 
			
		||||
    return ret;
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* add at the end of the file a new list of snapshots */
 | 
			
		||||
static int qcow2_write_snapshots(BlockDriverState *bs)
 | 
			
		||||
static int qcow_write_snapshots(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    QCowSnapshot *sn;
 | 
			
		||||
    QCowSnapshotHeader h;
 | 
			
		||||
    QCowSnapshotExtraData extra;
 | 
			
		||||
    int i, name_size, id_str_size, snapshots_size;
 | 
			
		||||
    struct {
 | 
			
		||||
        uint32_t nb_snapshots;
 | 
			
		||||
        uint64_t snapshots_offset;
 | 
			
		||||
    } QEMU_PACKED header_data;
 | 
			
		||||
    uint64_t data64;
 | 
			
		||||
    uint32_t data32;
 | 
			
		||||
    int64_t offset, snapshots_offset;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    /* compute the size of the snapshots */
 | 
			
		||||
    offset = 0;
 | 
			
		||||
@@ -172,100 +132,60 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
 | 
			
		||||
        sn = s->snapshots + i;
 | 
			
		||||
        offset = align_offset(offset, 8);
 | 
			
		||||
        offset += sizeof(h);
 | 
			
		||||
        offset += sizeof(extra);
 | 
			
		||||
        offset += strlen(sn->id_str);
 | 
			
		||||
        offset += strlen(sn->name);
 | 
			
		||||
    }
 | 
			
		||||
    snapshots_size = offset;
 | 
			
		||||
 | 
			
		||||
    /* Allocate space for the new snapshot list */
 | 
			
		||||
    snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
 | 
			
		||||
    bdrv_flush(bs->file);
 | 
			
		||||
    offset = snapshots_offset;
 | 
			
		||||
    if (offset < 0) {
 | 
			
		||||
        return offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Write all snapshots to the new list */
 | 
			
		||||
    for(i = 0; i < s->nb_snapshots; i++) {
 | 
			
		||||
        sn = s->snapshots + i;
 | 
			
		||||
        memset(&h, 0, sizeof(h));
 | 
			
		||||
        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
 | 
			
		||||
        h.l1_size = cpu_to_be32(sn->l1_size);
 | 
			
		||||
        /* If it doesn't fit in 32 bit, older implementations should treat it
 | 
			
		||||
         * as a disk-only snapshot rather than truncate the VM state */
 | 
			
		||||
        if (sn->vm_state_size <= 0xffffffff) {
 | 
			
		||||
        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
 | 
			
		||||
        }
 | 
			
		||||
        h.date_sec = cpu_to_be32(sn->date_sec);
 | 
			
		||||
        h.date_nsec = cpu_to_be32(sn->date_nsec);
 | 
			
		||||
        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
 | 
			
		||||
        h.extra_data_size = cpu_to_be32(sizeof(extra));
 | 
			
		||||
 | 
			
		||||
        memset(&extra, 0, sizeof(extra));
 | 
			
		||||
        extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
 | 
			
		||||
        extra.disk_size = cpu_to_be64(sn->disk_size);
 | 
			
		||||
 | 
			
		||||
        id_str_size = strlen(sn->id_str);
 | 
			
		||||
        name_size = strlen(sn->name);
 | 
			
		||||
        h.id_str_size = cpu_to_be16(id_str_size);
 | 
			
		||||
        h.name_size = cpu_to_be16(name_size);
 | 
			
		||||
        offset = align_offset(offset, 8);
 | 
			
		||||
 | 
			
		||||
        ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, offset, &h, sizeof(h)) < 0)
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        offset += sizeof(h);
 | 
			
		||||
 | 
			
		||||
        ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra));
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, offset, sn->id_str, id_str_size) < 0)
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        offset += sizeof(extra);
 | 
			
		||||
 | 
			
		||||
        ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        offset += id_str_size;
 | 
			
		||||
 | 
			
		||||
        ret = bdrv_pwrite(bs->file, offset, sn->name, name_size);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
        if (bdrv_pwrite_sync(s->hd, offset, sn->name, name_size) < 0)
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        offset += name_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Update the header to point to the new snapshot table. This requires the
 | 
			
		||||
     * new table and its refcounts to be stable on disk.
 | 
			
		||||
     */
 | 
			
		||||
    ret = bdrv_flush(bs);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    /* update the various header fields */
 | 
			
		||||
    data64 = cpu_to_be64(snapshots_offset);
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, snapshots_offset),
 | 
			
		||||
                    &data64, sizeof(data64)) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QEMU_BUILD_BUG_ON(offsetof(QCowHeader, snapshots_offset) !=
 | 
			
		||||
        offsetof(QCowHeader, nb_snapshots) + sizeof(header_data.nb_snapshots));
 | 
			
		||||
 | 
			
		||||
    header_data.nb_snapshots        = cpu_to_be32(s->nb_snapshots);
 | 
			
		||||
    header_data.snapshots_offset    = cpu_to_be64(snapshots_offset);
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
 | 
			
		||||
                           &header_data, sizeof(header_data));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    data32 = cpu_to_be32(s->nb_snapshots);
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, nb_snapshots),
 | 
			
		||||
                    &data32, sizeof(data32)) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* free the old snapshot table */
 | 
			
		||||
    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
 | 
			
		||||
    s->snapshots_offset = snapshots_offset;
 | 
			
		||||
    s->snapshots_size = snapshots_size;
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    return ret;
 | 
			
		||||
 fail:
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void find_new_snapshot_id(BlockDriverState *bs,
 | 
			
		||||
@@ -315,107 +235,79 @@ static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
 | 
			
		||||
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    QCowSnapshot *new_snapshot_list = NULL;
 | 
			
		||||
    QCowSnapshot *old_snapshot_list = NULL;
 | 
			
		||||
    QCowSnapshot sn1, *sn = &sn1;
 | 
			
		||||
    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
 | 
			
		||||
    int i, ret;
 | 
			
		||||
    uint64_t *l1_table = NULL;
 | 
			
		||||
    int64_t l1_table_offset;
 | 
			
		||||
 | 
			
		||||
    memset(sn, 0, sizeof(*sn));
 | 
			
		||||
 | 
			
		||||
    /* Generate an ID if it wasn't passed */
 | 
			
		||||
    if (sn_info->id_str[0] == '\0') {
 | 
			
		||||
        /* compute a new id */
 | 
			
		||||
        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Check that the ID is unique */
 | 
			
		||||
    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) {
 | 
			
		||||
    /* check that the ID is unique */
 | 
			
		||||
    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
 | 
			
		||||
        return -ENOENT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Populate sn with passed data */
 | 
			
		||||
    sn->id_str = g_strdup(sn_info->id_str);
 | 
			
		||||
    sn->name = g_strdup(sn_info->name);
 | 
			
		||||
 | 
			
		||||
    sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
 | 
			
		||||
    sn->id_str = qemu_strdup(sn_info->id_str);
 | 
			
		||||
    if (!sn->id_str)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    sn->name = qemu_strdup(sn_info->name);
 | 
			
		||||
    if (!sn->name)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    sn->vm_state_size = sn_info->vm_state_size;
 | 
			
		||||
    sn->date_sec = sn_info->date_sec;
 | 
			
		||||
    sn->date_nsec = sn_info->date_nsec;
 | 
			
		||||
    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
 | 
			
		||||
 | 
			
		||||
    /* Allocate the L1 table of the snapshot and copy the current one there. */
 | 
			
		||||
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
    /* create the L1 table of the snapshot */
 | 
			
		||||
    l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
 | 
			
		||||
    if (l1_table_offset < 0) {
 | 
			
		||||
        ret = l1_table_offset;
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sn->l1_table_offset = l1_table_offset;
 | 
			
		||||
    sn->l1_size = s->l1_size;
 | 
			
		||||
 | 
			
		||||
    l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
 | 
			
		||||
    if (s->l1_size != 0) {
 | 
			
		||||
        l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
 | 
			
		||||
    } else {
 | 
			
		||||
        l1_table = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < s->l1_size; i++) {
 | 
			
		||||
        l1_table[i] = cpu_to_be64(s->l1_table[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
 | 
			
		||||
                      s->l1_size * sizeof(uint64_t));
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, sn->l1_table_offset,
 | 
			
		||||
                    l1_table, s->l1_size * sizeof(uint64_t)) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free(l1_table);
 | 
			
		||||
    qemu_free(l1_table);
 | 
			
		||||
    l1_table = NULL;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Increase the refcounts of all clusters and make sure everything is
 | 
			
		||||
     * stable on disk before updating the snapshot table to contain a pointer
 | 
			
		||||
     * to the new L1 table.
 | 
			
		||||
     */
 | 
			
		||||
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_flush(bs);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Append the new snapshot to the snapshot list */
 | 
			
		||||
    new_snapshot_list = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
 | 
			
		||||
    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
 | 
			
		||||
    if (s->snapshots) {
 | 
			
		||||
        memcpy(new_snapshot_list, s->snapshots,
 | 
			
		||||
               s->nb_snapshots * sizeof(QCowSnapshot));
 | 
			
		||||
        old_snapshot_list = s->snapshots;
 | 
			
		||||
        memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
 | 
			
		||||
        qemu_free(s->snapshots);
 | 
			
		||||
    }
 | 
			
		||||
    s->snapshots = new_snapshot_list;
 | 
			
		||||
    s->snapshots = snapshots1;
 | 
			
		||||
    s->snapshots[s->nb_snapshots++] = *sn;
 | 
			
		||||
 | 
			
		||||
    ret = qcow2_write_snapshots(bs);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        g_free(s->snapshots);
 | 
			
		||||
        s->snapshots = old_snapshot_list;
 | 
			
		||||
    if (qcow_write_snapshots(bs) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free(old_snapshot_list);
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_ALLOC
 | 
			
		||||
    {
 | 
			
		||||
      BdrvCheckResult result = {0};
 | 
			
		||||
      qcow2_check_refcounts(bs, &result);
 | 
			
		||||
    }
 | 
			
		||||
    qcow2_check_refcounts(bs);
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    g_free(sn->id_str);
 | 
			
		||||
    g_free(sn->name);
 | 
			
		||||
    g_free(l1_table);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
 fail:
 | 
			
		||||
    qemu_free(sn->name);
 | 
			
		||||
    qemu_free(l1_table);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* copy the snapshot 'snapshot_name' into the current disk image */
 | 
			
		||||
@@ -423,167 +315,74 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    QCowSnapshot *sn;
 | 
			
		||||
    int i, snapshot_index;
 | 
			
		||||
    int cur_l1_bytes, sn_l1_bytes;
 | 
			
		||||
    int ret;
 | 
			
		||||
    uint64_t *sn_l1_table = NULL;
 | 
			
		||||
    int i, snapshot_index, l1_size2;
 | 
			
		||||
 | 
			
		||||
    /* Search the snapshot */
 | 
			
		||||
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
 | 
			
		||||
    if (snapshot_index < 0) {
 | 
			
		||||
    if (snapshot_index < 0)
 | 
			
		||||
        return -ENOENT;
 | 
			
		||||
    }
 | 
			
		||||
    sn = &s->snapshots[snapshot_index];
 | 
			
		||||
 | 
			
		||||
    if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
 | 
			
		||||
        error_report("qcow2: Loading snapshots with different disk "
 | 
			
		||||
            "size is not implemented");
 | 
			
		||||
        ret = -ENOTSUP;
 | 
			
		||||
    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Make sure that the current L1 table is big enough to contain the whole
 | 
			
		||||
     * L1 table of the snapshot. If the snapshot L1 table is smaller, the
 | 
			
		||||
     * current one must be padded with zeros.
 | 
			
		||||
     */
 | 
			
		||||
    ret = qcow2_grow_l1_table(bs, sn->l1_size, true);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    if (qcow2_grow_l1_table(bs, sn->l1_size) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cur_l1_bytes = s->l1_size * sizeof(uint64_t);
 | 
			
		||||
    sn_l1_bytes = sn->l1_size * sizeof(uint64_t);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Copy the snapshot L1 table to the current L1 table.
 | 
			
		||||
     *
 | 
			
		||||
     * Before overwriting the old current L1 table on disk, make sure to
 | 
			
		||||
     * increase all refcounts for the clusters referenced by the new one.
 | 
			
		||||
     * Decrease the refcount referenced by the old one only when the L1
 | 
			
		||||
     * table is overwritten.
 | 
			
		||||
     */
 | 
			
		||||
    sn_l1_table = g_malloc0(cur_l1_bytes);
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    s->l1_size = sn->l1_size;
 | 
			
		||||
    l1_size2 = s->l1_size * sizeof(uint64_t);
 | 
			
		||||
    /* copy the snapshot l1 table to the current l1 table */
 | 
			
		||||
    if (bdrv_pread(s->hd, sn->l1_table_offset,
 | 
			
		||||
                   s->l1_table, l1_size2) != l1_size2)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset,
 | 
			
		||||
                                         sn->l1_size, 1);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    if (bdrv_pwrite_sync(s->hd, s->l1_table_offset,
 | 
			
		||||
                    s->l1_table, l1_size2) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
 | 
			
		||||
                           cur_l1_bytes);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Decrease refcount of clusters of current L1 table.
 | 
			
		||||
     *
 | 
			
		||||
     * At this point, the in-memory s->l1_table points to the old L1 table,
 | 
			
		||||
     * whereas on disk we already have the new one.
 | 
			
		||||
     *
 | 
			
		||||
     * qcow2_update_snapshot_refcount special cases the current L1 table to use
 | 
			
		||||
     * the in-memory data instead of really using the offset to load a new one,
 | 
			
		||||
     * which is why this works.
 | 
			
		||||
     */
 | 
			
		||||
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset,
 | 
			
		||||
                                         s->l1_size, -1);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Now update the in-memory L1 table to be in sync with the on-disk one. We
 | 
			
		||||
     * need to do this even if updating refcounts failed.
 | 
			
		||||
     */
 | 
			
		||||
    for(i = 0;i < s->l1_size; i++) {
 | 
			
		||||
        s->l1_table[i] = be64_to_cpu(sn_l1_table[i]);
 | 
			
		||||
        be64_to_cpus(&s->l1_table[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free(sn_l1_table);
 | 
			
		||||
    sn_l1_table = NULL;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Update QCOW_OFLAG_COPIED in the active L1 table (it may have changed
 | 
			
		||||
     * when we decreased the refcount of the old snapshot.
 | 
			
		||||
     */
 | 
			
		||||
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_ALLOC
 | 
			
		||||
    {
 | 
			
		||||
        BdrvCheckResult result = {0};
 | 
			
		||||
        qcow2_check_refcounts(bs, &result);
 | 
			
		||||
    }
 | 
			
		||||
    qcow2_check_refcounts(bs);
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    g_free(sn_l1_table);
 | 
			
		||||
    return ret;
 | 
			
		||||
 fail:
 | 
			
		||||
    return -EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    QCowSnapshot sn;
 | 
			
		||||
    QCowSnapshot *sn;
 | 
			
		||||
    int snapshot_index, ret;
 | 
			
		||||
 | 
			
		||||
    /* Search the snapshot */
 | 
			
		||||
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
 | 
			
		||||
    if (snapshot_index < 0) {
 | 
			
		||||
    if (snapshot_index < 0)
 | 
			
		||||
        return -ENOENT;
 | 
			
		||||
    }
 | 
			
		||||
    sn = s->snapshots[snapshot_index];
 | 
			
		||||
    sn = &s->snapshots[snapshot_index];
 | 
			
		||||
 | 
			
		||||
    /* Remove it from the snapshot list */
 | 
			
		||||
    memmove(s->snapshots + snapshot_index,
 | 
			
		||||
            s->snapshots + snapshot_index + 1,
 | 
			
		||||
            (s->nb_snapshots - snapshot_index - 1) * sizeof(sn));
 | 
			
		||||
    s->nb_snapshots--;
 | 
			
		||||
    ret = qcow2_write_snapshots(bs);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * The snapshot is now unused, clean up. If we fail after this point, we
 | 
			
		||||
     * won't recover but just leak clusters.
 | 
			
		||||
     */
 | 
			
		||||
    g_free(sn.id_str);
 | 
			
		||||
    g_free(sn.name);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Now decrease the refcounts of clusters referenced by the snapshot and
 | 
			
		||||
     * free the L1 table.
 | 
			
		||||
     */
 | 
			
		||||
    ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
 | 
			
		||||
                                         sn.l1_size, -1);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t));
 | 
			
		||||
 | 
			
		||||
    /* must update the copied flag on the current cluster offsets */
 | 
			
		||||
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        return ret;
 | 
			
		||||
    qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
 | 
			
		||||
 | 
			
		||||
    qemu_free(sn->id_str);
 | 
			
		||||
    qemu_free(sn->name);
 | 
			
		||||
    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
 | 
			
		||||
    s->nb_snapshots--;
 | 
			
		||||
    ret = qcow_write_snapshots(bs);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        /* XXX: restore snapshot if error ? */
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_ALLOC
 | 
			
		||||
    {
 | 
			
		||||
        BdrvCheckResult result = {0};
 | 
			
		||||
        qcow2_check_refcounts(bs, &result);
 | 
			
		||||
    }
 | 
			
		||||
    qcow2_check_refcounts(bs);
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -600,7 +399,7 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 | 
			
		||||
        return s->nb_snapshots;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sn_tab = g_malloc0(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
 | 
			
		||||
    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
 | 
			
		||||
    for(i = 0; i < s->nb_snapshots; i++) {
 | 
			
		||||
        sn_info = sn_tab + i;
 | 
			
		||||
        sn = s->snapshots + i;
 | 
			
		||||
@@ -617,44 +416,3 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 | 
			
		||||
    return s->nb_snapshots;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
 | 
			
		||||
{
 | 
			
		||||
    int i, snapshot_index;
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    QCowSnapshot *sn;
 | 
			
		||||
    uint64_t *new_l1_table;
 | 
			
		||||
    int new_l1_bytes;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    assert(bs->read_only);
 | 
			
		||||
 | 
			
		||||
    /* Search the snapshot */
 | 
			
		||||
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name);
 | 
			
		||||
    if (snapshot_index < 0) {
 | 
			
		||||
        return -ENOENT;
 | 
			
		||||
    }
 | 
			
		||||
    sn = &s->snapshots[snapshot_index];
 | 
			
		||||
 | 
			
		||||
    /* Allocate and read in the snapshot's L1 table */
 | 
			
		||||
    new_l1_bytes = s->l1_size * sizeof(uint64_t);
 | 
			
		||||
    new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        g_free(new_l1_table);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Switch the L1 table */
 | 
			
		||||
    g_free(s->l1_table);
 | 
			
		||||
 | 
			
		||||
    s->l1_size = sn->l1_size;
 | 
			
		||||
    s->l1_table_offset = sn->l1_table_offset;
 | 
			
		||||
    s->l1_table = new_l1_table;
 | 
			
		||||
 | 
			
		||||
    for(i = 0;i < s->l1_size; i++) {
 | 
			
		||||
        be64_to_cpus(&s->l1_table[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1558
									
								
								block/qcow2.c
									
									
									
									
									
								
							
							
						
						
									
										1558
									
								
								block/qcow2.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										143
									
								
								block/qcow2.h
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								block/qcow2.h
									
									
									
									
									
								
							@@ -26,13 +26,13 @@
 | 
			
		||||
#define BLOCK_QCOW2_H
 | 
			
		||||
 | 
			
		||||
#include "aes.h"
 | 
			
		||||
#include "qemu-coroutine.h"
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_ALLOC
 | 
			
		||||
//#define DEBUG_ALLOC2
 | 
			
		||||
//#define DEBUG_EXT
 | 
			
		||||
 | 
			
		||||
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
 | 
			
		||||
#define QCOW_VERSION 2
 | 
			
		||||
 | 
			
		||||
#define QCOW_CRYPT_NONE 0
 | 
			
		||||
#define QCOW_CRYPT_AES  1
 | 
			
		||||
@@ -43,8 +43,6 @@
 | 
			
		||||
#define QCOW_OFLAG_COPIED     (1LL << 63)
 | 
			
		||||
/* indicate that the cluster is compressed (they never have the copied flag) */
 | 
			
		||||
#define QCOW_OFLAG_COMPRESSED (1LL << 62)
 | 
			
		||||
/* The cluster reads as all zeros */
 | 
			
		||||
#define QCOW_OFLAG_ZERO (1LL << 0)
 | 
			
		||||
 | 
			
		||||
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
 | 
			
		||||
 | 
			
		||||
@@ -53,11 +51,6 @@
 | 
			
		||||
 | 
			
		||||
#define L2_CACHE_SIZE 16
 | 
			
		||||
 | 
			
		||||
/* Must be at least 4 to cover all cases of refcount table growth */
 | 
			
		||||
#define REFCOUNT_CACHE_SIZE 4
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_CLUSTER_SIZE 65536
 | 
			
		||||
 | 
			
		||||
typedef struct QCowHeader {
 | 
			
		||||
    uint32_t magic;
 | 
			
		||||
    uint32_t version;
 | 
			
		||||
@@ -72,14 +65,6 @@ typedef struct QCowHeader {
 | 
			
		||||
    uint32_t refcount_table_clusters;
 | 
			
		||||
    uint32_t nb_snapshots;
 | 
			
		||||
    uint64_t snapshots_offset;
 | 
			
		||||
 | 
			
		||||
    /* The following fields are only valid for version >= 3 */
 | 
			
		||||
    uint64_t incompatible_features;
 | 
			
		||||
    uint64_t compatible_features;
 | 
			
		||||
    uint64_t autoclear_features;
 | 
			
		||||
 | 
			
		||||
    uint32_t refcount_order;
 | 
			
		||||
    uint32_t header_length;
 | 
			
		||||
} QCowHeader;
 | 
			
		||||
 | 
			
		||||
typedef struct QCowSnapshot {
 | 
			
		||||
@@ -87,36 +72,14 @@ typedef struct QCowSnapshot {
 | 
			
		||||
    uint32_t l1_size;
 | 
			
		||||
    char *id_str;
 | 
			
		||||
    char *name;
 | 
			
		||||
    uint64_t disk_size;
 | 
			
		||||
    uint64_t vm_state_size;
 | 
			
		||||
    uint32_t vm_state_size;
 | 
			
		||||
    uint32_t date_sec;
 | 
			
		||||
    uint32_t date_nsec;
 | 
			
		||||
    uint64_t vm_clock_nsec;
 | 
			
		||||
} QCowSnapshot;
 | 
			
		||||
 | 
			
		||||
struct Qcow2Cache;
 | 
			
		||||
typedef struct Qcow2Cache Qcow2Cache;
 | 
			
		||||
 | 
			
		||||
typedef struct Qcow2UnknownHeaderExtension {
 | 
			
		||||
    uint32_t magic;
 | 
			
		||||
    uint32_t len;
 | 
			
		||||
    QLIST_ENTRY(Qcow2UnknownHeaderExtension) next;
 | 
			
		||||
    uint8_t data[];
 | 
			
		||||
} Qcow2UnknownHeaderExtension;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    QCOW2_FEAT_TYPE_INCOMPATIBLE    = 0,
 | 
			
		||||
    QCOW2_FEAT_TYPE_COMPATIBLE      = 1,
 | 
			
		||||
    QCOW2_FEAT_TYPE_AUTOCLEAR       = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct Qcow2Feature {
 | 
			
		||||
    uint8_t type;
 | 
			
		||||
    uint8_t bit;
 | 
			
		||||
    char    name[46];
 | 
			
		||||
} QEMU_PACKED Qcow2Feature;
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVQcowState {
 | 
			
		||||
    BlockDriverState *hd;
 | 
			
		||||
    int cluster_bits;
 | 
			
		||||
    int cluster_size;
 | 
			
		||||
    int cluster_sectors;
 | 
			
		||||
@@ -129,10 +92,9 @@ typedef struct BDRVQcowState {
 | 
			
		||||
    uint64_t cluster_offset_mask;
 | 
			
		||||
    uint64_t l1_table_offset;
 | 
			
		||||
    uint64_t *l1_table;
 | 
			
		||||
 | 
			
		||||
    Qcow2Cache* l2_table_cache;
 | 
			
		||||
    Qcow2Cache* refcount_block_cache;
 | 
			
		||||
 | 
			
		||||
    uint64_t *l2_cache;
 | 
			
		||||
    uint64_t l2_cache_offsets[L2_CACHE_SIZE];
 | 
			
		||||
    uint32_t l2_cache_counts[L2_CACHE_SIZE];
 | 
			
		||||
    uint8_t *cluster_cache;
 | 
			
		||||
    uint8_t *cluster_data;
 | 
			
		||||
    uint64_t cluster_cache_offset;
 | 
			
		||||
@@ -141,11 +103,11 @@ typedef struct BDRVQcowState {
 | 
			
		||||
    uint64_t *refcount_table;
 | 
			
		||||
    uint64_t refcount_table_offset;
 | 
			
		||||
    uint32_t refcount_table_size;
 | 
			
		||||
    uint64_t refcount_block_cache_offset;
 | 
			
		||||
    uint16_t *refcount_block_cache;
 | 
			
		||||
    int64_t free_cluster_index;
 | 
			
		||||
    int64_t free_byte_offset;
 | 
			
		||||
 | 
			
		||||
    CoMutex lock;
 | 
			
		||||
 | 
			
		||||
    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
 | 
			
		||||
    uint32_t crypt_method_header;
 | 
			
		||||
    AES_KEY aes_encrypt_key;
 | 
			
		||||
@@ -154,17 +116,6 @@ typedef struct BDRVQcowState {
 | 
			
		||||
    int snapshots_size;
 | 
			
		||||
    int nb_snapshots;
 | 
			
		||||
    QCowSnapshot *snapshots;
 | 
			
		||||
 | 
			
		||||
    int flags;
 | 
			
		||||
    int qcow_version;
 | 
			
		||||
 | 
			
		||||
    uint64_t incompatible_features;
 | 
			
		||||
    uint64_t compatible_features;
 | 
			
		||||
    uint64_t autoclear_features;
 | 
			
		||||
 | 
			
		||||
    size_t unknown_header_fields_size;
 | 
			
		||||
    void* unknown_header_fields;
 | 
			
		||||
    QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
 | 
			
		||||
} BDRVQcowState;
 | 
			
		||||
 | 
			
		||||
/* XXX: use std qcow open function ? */
 | 
			
		||||
@@ -185,95 +136,62 @@ typedef struct QCowL2Meta
 | 
			
		||||
{
 | 
			
		||||
    uint64_t offset;
 | 
			
		||||
    uint64_t cluster_offset;
 | 
			
		||||
    uint64_t alloc_offset;
 | 
			
		||||
    int n_start;
 | 
			
		||||
    int nb_available;
 | 
			
		||||
    int nb_clusters;
 | 
			
		||||
    CoQueue dependent_requests;
 | 
			
		||||
    struct QCowL2Meta *depends_on;
 | 
			
		||||
    QLIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests;
 | 
			
		||||
 | 
			
		||||
    QLIST_ENTRY(QCowL2Meta) next_in_flight;
 | 
			
		||||
} QCowL2Meta;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    QCOW2_CLUSTER_UNALLOCATED,
 | 
			
		||||
    QCOW2_CLUSTER_NORMAL,
 | 
			
		||||
    QCOW2_CLUSTER_COMPRESSED,
 | 
			
		||||
    QCOW2_CLUSTER_ZERO
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
 | 
			
		||||
#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
 | 
			
		||||
#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
 | 
			
		||||
 | 
			
		||||
#define REFT_OFFSET_MASK 0xffffffffffffff00ULL
 | 
			
		||||
 | 
			
		||||
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
 | 
			
		||||
{
 | 
			
		||||
    return (size + (s->cluster_size - 1)) >> s->cluster_bits;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int size_to_l1(BDRVQcowState *s, int64_t size)
 | 
			
		||||
{
 | 
			
		||||
    int shift = s->cluster_bits + s->l2_bits;
 | 
			
		||||
    return (size + (1ULL << shift) - 1) >> shift;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int64_t align_offset(int64_t offset, int n)
 | 
			
		||||
{
 | 
			
		||||
    offset = (offset + n - 1) & ~(n - 1);
 | 
			
		||||
    return offset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int qcow2_get_cluster_type(uint64_t l2_entry)
 | 
			
		||||
{
 | 
			
		||||
    if (l2_entry & QCOW_OFLAG_COMPRESSED) {
 | 
			
		||||
        return QCOW2_CLUSTER_COMPRESSED;
 | 
			
		||||
    } else if (l2_entry & QCOW_OFLAG_ZERO) {
 | 
			
		||||
        return QCOW2_CLUSTER_ZERO;
 | 
			
		||||
    } else if (!(l2_entry & L2E_OFFSET_MASK)) {
 | 
			
		||||
        return QCOW2_CLUSTER_UNALLOCATED;
 | 
			
		||||
    } else {
 | 
			
		||||
        return QCOW2_CLUSTER_NORMAL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// FIXME Need qcow2_ prefix to global functions
 | 
			
		||||
 | 
			
		||||
/* qcow2.c functions */
 | 
			
		||||
int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
 | 
			
		||||
                  int64_t sector_num, int nb_sectors);
 | 
			
		||||
int qcow2_update_header(BlockDriverState *bs);
 | 
			
		||||
int qcow2_backing_read1(BlockDriverState *bs,
 | 
			
		||||
                  int64_t sector_num, uint8_t *buf, int nb_sectors);
 | 
			
		||||
 | 
			
		||||
/* qcow2-refcount.c functions */
 | 
			
		||||
int qcow2_refcount_init(BlockDriverState *bs);
 | 
			
		||||
void qcow2_refcount_close(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
 | 
			
		||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
 | 
			
		||||
    int nb_clusters);
 | 
			
		||||
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
 | 
			
		||||
void qcow2_free_clusters(BlockDriverState *bs,
 | 
			
		||||
    int64_t offset, int64_t size);
 | 
			
		||||
void qcow2_free_any_clusters(BlockDriverState *bs,
 | 
			
		||||
    uint64_t cluster_offset, int nb_clusters);
 | 
			
		||||
 | 
			
		||||
void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
 | 
			
		||||
    int64_t size);
 | 
			
		||||
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
 | 
			
		||||
    int64_t l1_table_offset, int l1_size, int addend);
 | 
			
		||||
 | 
			
		||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res);
 | 
			
		||||
int qcow2_check_refcounts(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
/* qcow2-cluster.c functions */
 | 
			
		||||
int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size);
 | 
			
		||||
int qcow2_grow_l1_table(BlockDriverState *bs, int min_size);
 | 
			
		||||
void qcow2_l2_cache_reset(BlockDriverState *bs);
 | 
			
		||||
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
 | 
			
		||||
int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
 | 
			
		||||
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
 | 
			
		||||
                     uint8_t *out_buf, const uint8_t *in_buf,
 | 
			
		||||
                     int nb_sectors, int enc,
 | 
			
		||||
                     const AES_KEY *key);
 | 
			
		||||
 | 
			
		||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
			
		||||
    int *num, uint64_t *cluster_offset);
 | 
			
		||||
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
			
		||||
    int *num);
 | 
			
		||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
			
		||||
    int n_start, int n_end, int *num, QCowL2Meta *m);
 | 
			
		||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
@@ -281,37 +199,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 | 
			
		||||
                                         int compressed_size);
 | 
			
		||||
 | 
			
		||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
 | 
			
		||||
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
 | 
			
		||||
    int nb_sectors);
 | 
			
		||||
int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
 | 
			
		||||
 | 
			
		||||
/* qcow2-snapshot.c functions */
 | 
			
		||||
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
 | 
			
		||||
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
 | 
			
		||||
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
 | 
			
		||||
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
 | 
			
		||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
 | 
			
		||||
 | 
			
		||||
void qcow2_free_snapshots(BlockDriverState *bs);
 | 
			
		||||
int qcow2_read_snapshots(BlockDriverState *bs);
 | 
			
		||||
 | 
			
		||||
/* qcow2-cache.c functions */
 | 
			
		||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
 | 
			
		||||
    bool writethrough);
 | 
			
		||||
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
 | 
			
		||||
bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
 | 
			
		||||
    bool enable);
 | 
			
		||||
 | 
			
		||||
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
 | 
			
		||||
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
 | 
			
		||||
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
 | 
			
		||||
    Qcow2Cache *dependency);
 | 
			
		||||
void qcow2_cache_depends_on_flush(Qcow2Cache *c);
 | 
			
		||||
 | 
			
		||||
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
 | 
			
		||||
    void **table);
 | 
			
		||||
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
 | 
			
		||||
    void **table);
 | 
			
		||||
int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,220 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU Enhanced Disk Format Consistency Check
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright IBM, Corp. 2010
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qed.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    BDRVQEDState *s;
 | 
			
		||||
    BdrvCheckResult *result;
 | 
			
		||||
    bool fix;                           /* whether to fix invalid offsets */
 | 
			
		||||
 | 
			
		||||
    uint64_t nclusters;
 | 
			
		||||
    uint32_t *used_clusters;            /* referenced cluster bitmap */
 | 
			
		||||
 | 
			
		||||
    QEDRequest request;
 | 
			
		||||
} QEDCheck;
 | 
			
		||||
 | 
			
		||||
static bool qed_test_bit(uint32_t *bitmap, uint64_t n) {
 | 
			
		||||
    return !!(bitmap[n / 32] & (1 << (n % 32)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qed_set_bit(uint32_t *bitmap, uint64_t n) {
 | 
			
		||||
    bitmap[n / 32] |= 1 << (n % 32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set bitmap bits for clusters
 | 
			
		||||
 *
 | 
			
		||||
 * @check:          Check structure
 | 
			
		||||
 * @offset:         Starting offset in bytes
 | 
			
		||||
 * @n:              Number of clusters
 | 
			
		||||
 */
 | 
			
		||||
static bool qed_set_used_clusters(QEDCheck *check, uint64_t offset,
 | 
			
		||||
                                  unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t cluster = qed_bytes_to_clusters(check->s, offset);
 | 
			
		||||
    unsigned int corruptions = 0;
 | 
			
		||||
 | 
			
		||||
    while (n-- != 0) {
 | 
			
		||||
        /* Clusters should only be referenced once */
 | 
			
		||||
        if (qed_test_bit(check->used_clusters, cluster)) {
 | 
			
		||||
            corruptions++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        qed_set_bit(check->used_clusters, cluster);
 | 
			
		||||
        cluster++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    check->result->corruptions += corruptions;
 | 
			
		||||
    return corruptions == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check an L2 table
 | 
			
		||||
 *
 | 
			
		||||
 * @ret:            Number of invalid cluster offsets
 | 
			
		||||
 */
 | 
			
		||||
static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQEDState *s = check->s;
 | 
			
		||||
    unsigned int i, num_invalid = 0;
 | 
			
		||||
    uint64_t last_offset = 0;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < s->table_nelems; i++) {
 | 
			
		||||
        uint64_t offset = table->offsets[i];
 | 
			
		||||
 | 
			
		||||
        if (qed_offset_is_unalloc_cluster(offset) ||
 | 
			
		||||
            qed_offset_is_zero_cluster(offset)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        check->result->bfi.allocated_clusters++;
 | 
			
		||||
        if (last_offset && (last_offset + s->header.cluster_size != offset)) {
 | 
			
		||||
            check->result->bfi.fragmented_clusters++;
 | 
			
		||||
        }
 | 
			
		||||
        last_offset = offset;
 | 
			
		||||
 | 
			
		||||
        /* Detect invalid cluster offset */
 | 
			
		||||
        if (!qed_check_cluster_offset(s, offset)) {
 | 
			
		||||
            if (check->fix) {
 | 
			
		||||
                table->offsets[i] = 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                check->result->corruptions++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            num_invalid++;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        qed_set_used_clusters(check, offset, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return num_invalid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Descend tables and check each cluster is referenced once only
 | 
			
		||||
 */
 | 
			
		||||
static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQEDState *s = check->s;
 | 
			
		||||
    unsigned int i, num_invalid_l1 = 0;
 | 
			
		||||
    int ret, last_error = 0;
 | 
			
		||||
 | 
			
		||||
    /* Mark L1 table clusters used */
 | 
			
		||||
    qed_set_used_clusters(check, s->header.l1_table_offset,
 | 
			
		||||
                          s->header.table_size);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < s->table_nelems; i++) {
 | 
			
		||||
        unsigned int num_invalid_l2;
 | 
			
		||||
        uint64_t offset = table->offsets[i];
 | 
			
		||||
 | 
			
		||||
        if (qed_offset_is_unalloc_cluster(offset)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Detect invalid L2 offset */
 | 
			
		||||
        if (!qed_check_table_offset(s, offset)) {
 | 
			
		||||
            /* Clear invalid offset */
 | 
			
		||||
            if (check->fix) {
 | 
			
		||||
                table->offsets[i] = 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                check->result->corruptions++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            num_invalid_l1++;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!qed_set_used_clusters(check, offset, s->header.table_size)) {
 | 
			
		||||
            continue; /* skip an invalid table */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ret = qed_read_l2_table_sync(s, &check->request, offset);
 | 
			
		||||
        if (ret) {
 | 
			
		||||
            check->result->check_errors++;
 | 
			
		||||
            last_error = ret;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        num_invalid_l2 = qed_check_l2_table(check,
 | 
			
		||||
                                            check->request.l2_table->table);
 | 
			
		||||
 | 
			
		||||
        /* Write out fixed L2 table */
 | 
			
		||||
        if (num_invalid_l2 > 0 && check->fix) {
 | 
			
		||||
            ret = qed_write_l2_table_sync(s, &check->request, 0,
 | 
			
		||||
                                          s->table_nelems, false);
 | 
			
		||||
            if (ret) {
 | 
			
		||||
                check->result->check_errors++;
 | 
			
		||||
                last_error = ret;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Drop reference to final table */
 | 
			
		||||
    qed_unref_l2_cache_entry(check->request.l2_table);
 | 
			
		||||
    check->request.l2_table = NULL;
 | 
			
		||||
 | 
			
		||||
    /* Write out fixed L1 table */
 | 
			
		||||
    if (num_invalid_l1 > 0 && check->fix) {
 | 
			
		||||
        ret = qed_write_l1_table_sync(s, 0, s->table_nelems);
 | 
			
		||||
        if (ret) {
 | 
			
		||||
            check->result->check_errors++;
 | 
			
		||||
            last_error = ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return last_error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check for unreferenced (leaked) clusters
 | 
			
		||||
 */
 | 
			
		||||
static void qed_check_for_leaks(QEDCheck *check)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQEDState *s = check->s;
 | 
			
		||||
    uint64_t i;
 | 
			
		||||
 | 
			
		||||
    for (i = s->header.header_size; i < check->nclusters; i++) {
 | 
			
		||||
        if (!qed_test_bit(check->used_clusters, i)) {
 | 
			
		||||
            check->result->leaks++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
 | 
			
		||||
{
 | 
			
		||||
    QEDCheck check = {
 | 
			
		||||
        .s = s,
 | 
			
		||||
        .result = result,
 | 
			
		||||
        .nclusters = qed_bytes_to_clusters(s, s->file_size),
 | 
			
		||||
        .request = { .l2_table = NULL },
 | 
			
		||||
        .fix = fix,
 | 
			
		||||
    };
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    check.used_clusters = g_malloc0(((check.nclusters + 31) / 32) *
 | 
			
		||||
                                       sizeof(check.used_clusters[0]));
 | 
			
		||||
 | 
			
		||||
    check.result->bfi.total_clusters =
 | 
			
		||||
        (s->header.image_size + s->header.cluster_size - 1) /
 | 
			
		||||
            s->header.cluster_size;
 | 
			
		||||
    ret = qed_check_l1_table(&check, s->l1_table);
 | 
			
		||||
    if (ret == 0) {
 | 
			
		||||
        /* Only check for leaks if entire image was scanned successfully */
 | 
			
		||||
        qed_check_for_leaks(&check);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free(check.used_clusters);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,165 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU Enhanced Disk Format Cluster functions
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright IBM, Corp. 2010
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 | 
			
		||||
 *  Anthony Liguori   <aliguori@us.ibm.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qed.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Count the number of contiguous data clusters
 | 
			
		||||
 *
 | 
			
		||||
 * @s:              QED state
 | 
			
		||||
 * @table:          L2 table
 | 
			
		||||
 * @index:          First cluster index
 | 
			
		||||
 * @n:              Maximum number of clusters
 | 
			
		||||
 * @offset:         Set to first cluster offset
 | 
			
		||||
 *
 | 
			
		||||
 * This function scans tables for contiguous clusters.  A contiguous run of
 | 
			
		||||
 * clusters may be allocated, unallocated, or zero.
 | 
			
		||||
 */
 | 
			
		||||
static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
 | 
			
		||||
                                                  QEDTable *table,
 | 
			
		||||
                                                  unsigned int index,
 | 
			
		||||
                                                  unsigned int n,
 | 
			
		||||
                                                  uint64_t *offset)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int end = MIN(index + n, s->table_nelems);
 | 
			
		||||
    uint64_t last = table->offsets[index];
 | 
			
		||||
    unsigned int i;
 | 
			
		||||
 | 
			
		||||
    *offset = last;
 | 
			
		||||
 | 
			
		||||
    for (i = index + 1; i < end; i++) {
 | 
			
		||||
        if (qed_offset_is_unalloc_cluster(last)) {
 | 
			
		||||
            /* Counting unallocated clusters */
 | 
			
		||||
            if (!qed_offset_is_unalloc_cluster(table->offsets[i])) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (qed_offset_is_zero_cluster(last)) {
 | 
			
		||||
            /* Counting zero clusters */
 | 
			
		||||
            if (!qed_offset_is_zero_cluster(table->offsets[i])) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Counting allocated clusters */
 | 
			
		||||
            if (table->offsets[i] != last + s->header.cluster_size) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            last = table->offsets[i];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return i - index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    BDRVQEDState *s;
 | 
			
		||||
    uint64_t pos;
 | 
			
		||||
    size_t len;
 | 
			
		||||
 | 
			
		||||
    QEDRequest *request;
 | 
			
		||||
 | 
			
		||||
    /* User callback */
 | 
			
		||||
    QEDFindClusterFunc *cb;
 | 
			
		||||
    void *opaque;
 | 
			
		||||
} QEDFindClusterCB;
 | 
			
		||||
 | 
			
		||||
static void qed_find_cluster_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    QEDFindClusterCB *find_cluster_cb = opaque;
 | 
			
		||||
    BDRVQEDState *s = find_cluster_cb->s;
 | 
			
		||||
    QEDRequest *request = find_cluster_cb->request;
 | 
			
		||||
    uint64_t offset = 0;
 | 
			
		||||
    size_t len = 0;
 | 
			
		||||
    unsigned int index;
 | 
			
		||||
    unsigned int n;
 | 
			
		||||
 | 
			
		||||
    if (ret) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    index = qed_l2_index(s, find_cluster_cb->pos);
 | 
			
		||||
    n = qed_bytes_to_clusters(s,
 | 
			
		||||
                              qed_offset_into_cluster(s, find_cluster_cb->pos) +
 | 
			
		||||
                              find_cluster_cb->len);
 | 
			
		||||
    n = qed_count_contiguous_clusters(s, request->l2_table->table,
 | 
			
		||||
                                      index, n, &offset);
 | 
			
		||||
 | 
			
		||||
    if (qed_offset_is_unalloc_cluster(offset)) {
 | 
			
		||||
        ret = QED_CLUSTER_L2;
 | 
			
		||||
    } else if (qed_offset_is_zero_cluster(offset)) {
 | 
			
		||||
        ret = QED_CLUSTER_ZERO;
 | 
			
		||||
    } else if (qed_check_cluster_offset(s, offset)) {
 | 
			
		||||
        ret = QED_CLUSTER_FOUND;
 | 
			
		||||
    } else {
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
 | 
			
		||||
              qed_offset_into_cluster(s, find_cluster_cb->pos));
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
 | 
			
		||||
    g_free(find_cluster_cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find the offset of a data cluster
 | 
			
		||||
 *
 | 
			
		||||
 * @s:          QED state
 | 
			
		||||
 * @request:    L2 cache entry
 | 
			
		||||
 * @pos:        Byte position in device
 | 
			
		||||
 * @len:        Number of bytes
 | 
			
		||||
 * @cb:         Completion function
 | 
			
		||||
 * @opaque:     User data for completion function
 | 
			
		||||
 *
 | 
			
		||||
 * This function translates a position in the block device to an offset in the
 | 
			
		||||
 * image file.  It invokes the cb completion callback to report back the
 | 
			
		||||
 * translated offset or unallocated range in the image file.
 | 
			
		||||
 *
 | 
			
		||||
 * If the L2 table exists, request->l2_table points to the L2 table cache entry
 | 
			
		||||
 * and the caller must free the reference when they are finished.  The cache
 | 
			
		||||
 * entry is exposed in this way to avoid callers having to read the L2 table
 | 
			
		||||
 * again later during request processing.  If request->l2_table is non-NULL it
 | 
			
		||||
 * will be unreferenced before taking on the new cache entry.
 | 
			
		||||
 */
 | 
			
		||||
void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
 | 
			
		||||
                      size_t len, QEDFindClusterFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    QEDFindClusterCB *find_cluster_cb;
 | 
			
		||||
    uint64_t l2_offset;
 | 
			
		||||
 | 
			
		||||
    /* Limit length to L2 boundary.  Requests are broken up at the L2 boundary
 | 
			
		||||
     * so that a request acts on one L2 table at a time.
 | 
			
		||||
     */
 | 
			
		||||
    len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
 | 
			
		||||
 | 
			
		||||
    l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
 | 
			
		||||
    if (qed_offset_is_unalloc_cluster(l2_offset)) {
 | 
			
		||||
        cb(opaque, QED_CLUSTER_L1, 0, len);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (!qed_check_table_offset(s, l2_offset)) {
 | 
			
		||||
        cb(opaque, -EINVAL, 0, 0);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    find_cluster_cb = g_malloc(sizeof(*find_cluster_cb));
 | 
			
		||||
    find_cluster_cb->s = s;
 | 
			
		||||
    find_cluster_cb->pos = pos;
 | 
			
		||||
    find_cluster_cb->len = len;
 | 
			
		||||
    find_cluster_cb->cb = cb;
 | 
			
		||||
    find_cluster_cb->opaque = opaque;
 | 
			
		||||
    find_cluster_cb->request = request;
 | 
			
		||||
 | 
			
		||||
    qed_read_l2_table(s, request, l2_offset,
 | 
			
		||||
                      qed_find_cluster_cb, find_cluster_cb);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU Enhanced Disk Format
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright IBM, Corp. 2010
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qed.h"
 | 
			
		||||
 | 
			
		||||
void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    GenericCB *gencb = g_malloc(len);
 | 
			
		||||
    gencb->cb = cb;
 | 
			
		||||
    gencb->opaque = opaque;
 | 
			
		||||
    return gencb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gencb_complete(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    GenericCB *gencb = opaque;
 | 
			
		||||
    BlockDriverCompletionFunc *cb = gencb->cb;
 | 
			
		||||
    void *user_opaque = gencb->opaque;
 | 
			
		||||
 | 
			
		||||
    g_free(gencb);
 | 
			
		||||
    cb(user_opaque, ret);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,187 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU Enhanced Disk Format L2 Cache
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright IBM, Corp. 2010
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *  Anthony Liguori   <aliguori@us.ibm.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * L2 table cache usage is as follows:
 | 
			
		||||
 *
 | 
			
		||||
 * An open image has one L2 table cache that is used to avoid accessing the
 | 
			
		||||
 * image file for recently referenced L2 tables.
 | 
			
		||||
 *
 | 
			
		||||
 * Cluster offset lookup translates the logical offset within the block device
 | 
			
		||||
 * to a cluster offset within the image file.  This is done by indexing into
 | 
			
		||||
 * the L1 and L2 tables which store cluster offsets.  It is here where the L2
 | 
			
		||||
 * table cache serves up recently referenced L2 tables.
 | 
			
		||||
 *
 | 
			
		||||
 * If there is a cache miss, that L2 table is read from the image file and
 | 
			
		||||
 * committed to the cache.  Subsequent accesses to that L2 table will be served
 | 
			
		||||
 * from the cache until the table is evicted from the cache.
 | 
			
		||||
 *
 | 
			
		||||
 * L2 tables are also committed to the cache when new L2 tables are allocated
 | 
			
		||||
 * in the image file.  Since the L2 table cache is write-through, the new L2
 | 
			
		||||
 * table is first written out to the image file and then committed to the
 | 
			
		||||
 * cache.
 | 
			
		||||
 *
 | 
			
		||||
 * Multiple I/O requests may be using an L2 table cache entry at any given
 | 
			
		||||
 * time.  That means an entry may be in use across several requests and
 | 
			
		||||
 * reference counting is needed to free the entry at the correct time.  In
 | 
			
		||||
 * particular, an entry evicted from the cache will only be freed once all
 | 
			
		||||
 * references are dropped.
 | 
			
		||||
 *
 | 
			
		||||
 * An in-flight I/O request will hold a reference to a L2 table cache entry for
 | 
			
		||||
 * the period during which it needs to access the L2 table.  This includes
 | 
			
		||||
 * cluster offset lookup, L2 table allocation, and L2 table update when a new
 | 
			
		||||
 * data cluster has been allocated.
 | 
			
		||||
 *
 | 
			
		||||
 * An interesting case occurs when two requests need to access an L2 table that
 | 
			
		||||
 * is not in the cache.  Since the operation to read the table from the image
 | 
			
		||||
 * file takes some time to complete, both requests may see a cache miss and
 | 
			
		||||
 * start reading the L2 table from the image file.  The first to finish will
 | 
			
		||||
 * commit its L2 table into the cache.  When the second tries to commit its
 | 
			
		||||
 * table will be deleted in favor of the existing cache entry.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
#include "qed.h"
 | 
			
		||||
 | 
			
		||||
/* Each L2 holds 2GB so this let's us fully cache a 100GB disk */
 | 
			
		||||
#define MAX_L2_CACHE_SIZE 50
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialize the L2 cache
 | 
			
		||||
 */
 | 
			
		||||
void qed_init_l2_cache(L2TableCache *l2_cache)
 | 
			
		||||
{
 | 
			
		||||
    QTAILQ_INIT(&l2_cache->entries);
 | 
			
		||||
    l2_cache->n_entries = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Free the L2 cache
 | 
			
		||||
 */
 | 
			
		||||
void qed_free_l2_cache(L2TableCache *l2_cache)
 | 
			
		||||
{
 | 
			
		||||
    CachedL2Table *entry, *next_entry;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH_SAFE(entry, &l2_cache->entries, node, next_entry) {
 | 
			
		||||
        qemu_vfree(entry->table);
 | 
			
		||||
        g_free(entry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Allocate an uninitialized entry from the cache
 | 
			
		||||
 *
 | 
			
		||||
 * The returned entry has a reference count of 1 and is owned by the caller.
 | 
			
		||||
 * The caller must allocate the actual table field for this entry and it must
 | 
			
		||||
 * be freeable using qemu_vfree().
 | 
			
		||||
 */
 | 
			
		||||
CachedL2Table *qed_alloc_l2_cache_entry(L2TableCache *l2_cache)
 | 
			
		||||
{
 | 
			
		||||
    CachedL2Table *entry;
 | 
			
		||||
 | 
			
		||||
    entry = g_malloc0(sizeof(*entry));
 | 
			
		||||
    entry->ref++;
 | 
			
		||||
 | 
			
		||||
    trace_qed_alloc_l2_cache_entry(l2_cache, entry);
 | 
			
		||||
 | 
			
		||||
    return entry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Decrease an entry's reference count and free if necessary when the reference
 | 
			
		||||
 * count drops to zero.
 | 
			
		||||
 */
 | 
			
		||||
void qed_unref_l2_cache_entry(CachedL2Table *entry)
 | 
			
		||||
{
 | 
			
		||||
    if (!entry) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    entry->ref--;
 | 
			
		||||
    trace_qed_unref_l2_cache_entry(entry, entry->ref);
 | 
			
		||||
    if (entry->ref == 0) {
 | 
			
		||||
        qemu_vfree(entry->table);
 | 
			
		||||
        g_free(entry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find an entry in the L2 cache.  This may return NULL and it's up to the
 | 
			
		||||
 * caller to satisfy the cache miss.
 | 
			
		||||
 *
 | 
			
		||||
 * For a cached entry, this function increases the reference count and returns
 | 
			
		||||
 * the entry.
 | 
			
		||||
 */
 | 
			
		||||
CachedL2Table *qed_find_l2_cache_entry(L2TableCache *l2_cache, uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    CachedL2Table *entry;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(entry, &l2_cache->entries, node) {
 | 
			
		||||
        if (entry->offset == offset) {
 | 
			
		||||
            trace_qed_find_l2_cache_entry(l2_cache, entry, offset, entry->ref);
 | 
			
		||||
            entry->ref++;
 | 
			
		||||
            return entry;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Commit an L2 cache entry into the cache.  This is meant to be used as part of
 | 
			
		||||
 * the process to satisfy a cache miss.  A caller would allocate an entry which
 | 
			
		||||
 * is not actually in the L2 cache and then once the entry was valid and
 | 
			
		||||
 * present on disk, the entry can be committed into the cache.
 | 
			
		||||
 *
 | 
			
		||||
 * Since the cache is write-through, it's important that this function is not
 | 
			
		||||
 * called until the entry is present on disk and the L1 has been updated to
 | 
			
		||||
 * point to the entry.
 | 
			
		||||
 *
 | 
			
		||||
 * N.B. This function steals a reference to the l2_table from the caller so the
 | 
			
		||||
 * caller must obtain a new reference by issuing a call to
 | 
			
		||||
 * qed_find_l2_cache_entry().
 | 
			
		||||
 */
 | 
			
		||||
void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table)
 | 
			
		||||
{
 | 
			
		||||
    CachedL2Table *entry;
 | 
			
		||||
 | 
			
		||||
    entry = qed_find_l2_cache_entry(l2_cache, l2_table->offset);
 | 
			
		||||
    if (entry) {
 | 
			
		||||
        qed_unref_l2_cache_entry(entry);
 | 
			
		||||
        qed_unref_l2_cache_entry(l2_table);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Evict an unused cache entry so we have space.  If all entries are in use
 | 
			
		||||
     * we can grow the cache temporarily and we try to shrink back down later.
 | 
			
		||||
     */
 | 
			
		||||
    if (l2_cache->n_entries >= MAX_L2_CACHE_SIZE) {
 | 
			
		||||
        CachedL2Table *next;
 | 
			
		||||
        QTAILQ_FOREACH_SAFE(entry, &l2_cache->entries, node, next) {
 | 
			
		||||
            if (entry->ref > 1) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            QTAILQ_REMOVE(&l2_cache->entries, entry, node);
 | 
			
		||||
            l2_cache->n_entries--;
 | 
			
		||||
            qed_unref_l2_cache_entry(entry);
 | 
			
		||||
 | 
			
		||||
            /* Stop evicting when we've shrunk back to max size */
 | 
			
		||||
            if (l2_cache->n_entries < MAX_L2_CACHE_SIZE) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    l2_cache->n_entries++;
 | 
			
		||||
    QTAILQ_INSERT_TAIL(&l2_cache->entries, l2_table, node);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,297 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU Enhanced Disk Format Table I/O
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright IBM, Corp. 2010
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 | 
			
		||||
 *  Anthony Liguori   <aliguori@us.ibm.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
#include "qemu_socket.h" /* for EINPROGRESS on Windows */
 | 
			
		||||
#include "qed.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    GenericCB gencb;
 | 
			
		||||
    BDRVQEDState *s;
 | 
			
		||||
    QEDTable *table;
 | 
			
		||||
 | 
			
		||||
    struct iovec iov;
 | 
			
		||||
    QEMUIOVector qiov;
 | 
			
		||||
} QEDReadTableCB;
 | 
			
		||||
 | 
			
		||||
static void qed_read_table_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    QEDReadTableCB *read_table_cb = opaque;
 | 
			
		||||
    QEDTable *table = read_table_cb->table;
 | 
			
		||||
    int noffsets = read_table_cb->qiov.size / sizeof(uint64_t);
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    /* Handle I/O error */
 | 
			
		||||
    if (ret) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Byteswap offsets */
 | 
			
		||||
    for (i = 0; i < noffsets; i++) {
 | 
			
		||||
        table->offsets[i] = le64_to_cpu(table->offsets[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    /* Completion */
 | 
			
		||||
    trace_qed_read_table_cb(read_table_cb->s, read_table_cb->table, ret);
 | 
			
		||||
    gencb_complete(&read_table_cb->gencb, ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
 | 
			
		||||
                           BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    QEDReadTableCB *read_table_cb = gencb_alloc(sizeof(*read_table_cb),
 | 
			
		||||
                                                cb, opaque);
 | 
			
		||||
    QEMUIOVector *qiov = &read_table_cb->qiov;
 | 
			
		||||
 | 
			
		||||
    trace_qed_read_table(s, offset, table);
 | 
			
		||||
 | 
			
		||||
    read_table_cb->s = s;
 | 
			
		||||
    read_table_cb->table = table;
 | 
			
		||||
    read_table_cb->iov.iov_base = table->offsets,
 | 
			
		||||
    read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size,
 | 
			
		||||
 | 
			
		||||
    qemu_iovec_init_external(qiov, &read_table_cb->iov, 1);
 | 
			
		||||
    bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov,
 | 
			
		||||
                   qiov->size / BDRV_SECTOR_SIZE,
 | 
			
		||||
                   qed_read_table_cb, read_table_cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    GenericCB gencb;
 | 
			
		||||
    BDRVQEDState *s;
 | 
			
		||||
    QEDTable *orig_table;
 | 
			
		||||
    QEDTable *table;
 | 
			
		||||
    bool flush;             /* flush after write? */
 | 
			
		||||
 | 
			
		||||
    struct iovec iov;
 | 
			
		||||
    QEMUIOVector qiov;
 | 
			
		||||
} QEDWriteTableCB;
 | 
			
		||||
 | 
			
		||||
static void qed_write_table_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    QEDWriteTableCB *write_table_cb = opaque;
 | 
			
		||||
 | 
			
		||||
    trace_qed_write_table_cb(write_table_cb->s,
 | 
			
		||||
                             write_table_cb->orig_table,
 | 
			
		||||
                             write_table_cb->flush,
 | 
			
		||||
                             ret);
 | 
			
		||||
 | 
			
		||||
    if (ret) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (write_table_cb->flush) {
 | 
			
		||||
        /* We still need to flush first */
 | 
			
		||||
        write_table_cb->flush = false;
 | 
			
		||||
        bdrv_aio_flush(write_table_cb->s->bs, qed_write_table_cb,
 | 
			
		||||
                       write_table_cb);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    qemu_vfree(write_table_cb->table);
 | 
			
		||||
    gencb_complete(&write_table_cb->gencb, ret);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Write out an updated part or all of a table
 | 
			
		||||
 *
 | 
			
		||||
 * @s:          QED state
 | 
			
		||||
 * @offset:     Offset of table in image file, in bytes
 | 
			
		||||
 * @table:      Table
 | 
			
		||||
 * @index:      Index of first element
 | 
			
		||||
 * @n:          Number of elements
 | 
			
		||||
 * @flush:      Whether or not to sync to disk
 | 
			
		||||
 * @cb:         Completion function
 | 
			
		||||
 * @opaque:     Argument for completion function
 | 
			
		||||
 */
 | 
			
		||||
static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
 | 
			
		||||
                            unsigned int index, unsigned int n, bool flush,
 | 
			
		||||
                            BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    QEDWriteTableCB *write_table_cb;
 | 
			
		||||
    unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
 | 
			
		||||
    unsigned int start, end, i;
 | 
			
		||||
    size_t len_bytes;
 | 
			
		||||
 | 
			
		||||
    trace_qed_write_table(s, offset, table, index, n);
 | 
			
		||||
 | 
			
		||||
    /* Calculate indices of the first and one after last elements */
 | 
			
		||||
    start = index & ~sector_mask;
 | 
			
		||||
    end = (index + n + sector_mask) & ~sector_mask;
 | 
			
		||||
 | 
			
		||||
    len_bytes = (end - start) * sizeof(uint64_t);
 | 
			
		||||
 | 
			
		||||
    write_table_cb = gencb_alloc(sizeof(*write_table_cb), cb, opaque);
 | 
			
		||||
    write_table_cb->s = s;
 | 
			
		||||
    write_table_cb->orig_table = table;
 | 
			
		||||
    write_table_cb->flush = flush;
 | 
			
		||||
    write_table_cb->table = qemu_blockalign(s->bs, len_bytes);
 | 
			
		||||
    write_table_cb->iov.iov_base = write_table_cb->table->offsets;
 | 
			
		||||
    write_table_cb->iov.iov_len = len_bytes;
 | 
			
		||||
    qemu_iovec_init_external(&write_table_cb->qiov, &write_table_cb->iov, 1);
 | 
			
		||||
 | 
			
		||||
    /* Byteswap table */
 | 
			
		||||
    for (i = start; i < end; i++) {
 | 
			
		||||
        uint64_t le_offset = cpu_to_le64(table->offsets[i]);
 | 
			
		||||
        write_table_cb->table->offsets[i - start] = le_offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Adjust for offset into table */
 | 
			
		||||
    offset += start * sizeof(uint64_t);
 | 
			
		||||
 | 
			
		||||
    bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
 | 
			
		||||
                    &write_table_cb->qiov,
 | 
			
		||||
                    write_table_cb->qiov.size / BDRV_SECTOR_SIZE,
 | 
			
		||||
                    qed_write_table_cb, write_table_cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Propagate return value from async callback
 | 
			
		||||
 */
 | 
			
		||||
static void qed_sync_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    *(int *)opaque = ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qed_read_l1_table_sync(BDRVQEDState *s)
 | 
			
		||||
{
 | 
			
		||||
    int ret = -EINPROGRESS;
 | 
			
		||||
 | 
			
		||||
    qed_read_table(s, s->header.l1_table_offset,
 | 
			
		||||
                   s->l1_table, qed_sync_cb, &ret);
 | 
			
		||||
    while (ret == -EINPROGRESS) {
 | 
			
		||||
        qemu_aio_wait();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
 | 
			
		||||
                        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
 | 
			
		||||
    qed_write_table(s, s->header.l1_table_offset,
 | 
			
		||||
                    s->l1_table, index, n, false, cb, opaque);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
 | 
			
		||||
                            unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
    int ret = -EINPROGRESS;
 | 
			
		||||
 | 
			
		||||
    qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
 | 
			
		||||
    while (ret == -EINPROGRESS) {
 | 
			
		||||
        qemu_aio_wait();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    GenericCB gencb;
 | 
			
		||||
    BDRVQEDState *s;
 | 
			
		||||
    uint64_t l2_offset;
 | 
			
		||||
    QEDRequest *request;
 | 
			
		||||
} QEDReadL2TableCB;
 | 
			
		||||
 | 
			
		||||
static void qed_read_l2_table_cb(void *opaque, int ret)
 | 
			
		||||
{
 | 
			
		||||
    QEDReadL2TableCB *read_l2_table_cb = opaque;
 | 
			
		||||
    QEDRequest *request = read_l2_table_cb->request;
 | 
			
		||||
    BDRVQEDState *s = read_l2_table_cb->s;
 | 
			
		||||
    CachedL2Table *l2_table = request->l2_table;
 | 
			
		||||
    uint64_t l2_offset = read_l2_table_cb->l2_offset;
 | 
			
		||||
 | 
			
		||||
    if (ret) {
 | 
			
		||||
        /* can't trust loaded L2 table anymore */
 | 
			
		||||
        qed_unref_l2_cache_entry(l2_table);
 | 
			
		||||
        request->l2_table = NULL;
 | 
			
		||||
    } else {
 | 
			
		||||
        l2_table->offset = l2_offset;
 | 
			
		||||
 | 
			
		||||
        qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
 | 
			
		||||
 | 
			
		||||
        /* This is guaranteed to succeed because we just committed the entry
 | 
			
		||||
         * to the cache.
 | 
			
		||||
         */
 | 
			
		||||
        request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
 | 
			
		||||
        assert(request->l2_table != NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gencb_complete(&read_l2_table_cb->gencb, ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
 | 
			
		||||
                       BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    QEDReadL2TableCB *read_l2_table_cb;
 | 
			
		||||
 | 
			
		||||
    qed_unref_l2_cache_entry(request->l2_table);
 | 
			
		||||
 | 
			
		||||
    /* Check for cached L2 entry */
 | 
			
		||||
    request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
 | 
			
		||||
    if (request->l2_table) {
 | 
			
		||||
        cb(opaque, 0);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
 | 
			
		||||
    request->l2_table->table = qed_alloc_table(s);
 | 
			
		||||
 | 
			
		||||
    read_l2_table_cb = gencb_alloc(sizeof(*read_l2_table_cb), cb, opaque);
 | 
			
		||||
    read_l2_table_cb->s = s;
 | 
			
		||||
    read_l2_table_cb->l2_offset = offset;
 | 
			
		||||
    read_l2_table_cb->request = request;
 | 
			
		||||
 | 
			
		||||
    BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
 | 
			
		||||
    qed_read_table(s, offset, request->l2_table->table,
 | 
			
		||||
                   qed_read_l2_table_cb, read_l2_table_cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    int ret = -EINPROGRESS;
 | 
			
		||||
 | 
			
		||||
    qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
 | 
			
		||||
    while (ret == -EINPROGRESS) {
 | 
			
		||||
        qemu_aio_wait();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
 | 
			
		||||
                        unsigned int index, unsigned int n, bool flush,
 | 
			
		||||
                        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
 | 
			
		||||
    qed_write_table(s, request->l2_table->offset,
 | 
			
		||||
                    request->l2_table->table, index, n, flush, cb, opaque);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 | 
			
		||||
                            unsigned int index, unsigned int n, bool flush)
 | 
			
		||||
{
 | 
			
		||||
    int ret = -EINPROGRESS;
 | 
			
		||||
 | 
			
		||||
    qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
 | 
			
		||||
    while (ret == -EINPROGRESS) {
 | 
			
		||||
        qemu_aio_wait();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1574
									
								
								block/qed.c
									
									
									
									
									
								
							
							
						
						
									
										1574
									
								
								block/qed.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										339
									
								
								block/qed.h
									
									
									
									
									
								
							
							
						
						
									
										339
									
								
								block/qed.h
									
									
									
									
									
								
							@@ -1,339 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU Enhanced Disk Format
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright IBM, Corp. 2010
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 | 
			
		||||
 *  Anthony Liguori   <aliguori@us.ibm.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef BLOCK_QED_H
 | 
			
		||||
#define BLOCK_QED_H
 | 
			
		||||
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
 | 
			
		||||
/* The layout of a QED file is as follows:
 | 
			
		||||
 *
 | 
			
		||||
 * +--------+----------+----------+----------+-----+
 | 
			
		||||
 * | header | L1 table | cluster0 | cluster1 | ... |
 | 
			
		||||
 * +--------+----------+----------+----------+-----+
 | 
			
		||||
 *
 | 
			
		||||
 * There is a 2-level pagetable for cluster allocation:
 | 
			
		||||
 *
 | 
			
		||||
 *                     +----------+
 | 
			
		||||
 *                     | L1 table |
 | 
			
		||||
 *                     +----------+
 | 
			
		||||
 *                ,------'  |  '------.
 | 
			
		||||
 *           +----------+   |    +----------+
 | 
			
		||||
 *           | L2 table |  ...   | L2 table |
 | 
			
		||||
 *           +----------+        +----------+
 | 
			
		||||
 *       ,------'  |  '------.
 | 
			
		||||
 *  +----------+   |    +----------+
 | 
			
		||||
 *  |   Data   |  ...   |   Data   |
 | 
			
		||||
 *  +----------+        +----------+
 | 
			
		||||
 *
 | 
			
		||||
 * The L1 table is fixed size and always present.  L2 tables are allocated on
 | 
			
		||||
 * demand.  The L1 table size determines the maximum possible image size; it
 | 
			
		||||
 * can be influenced using the cluster_size and table_size values.
 | 
			
		||||
 *
 | 
			
		||||
 * All fields are little-endian on disk.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    QED_MAGIC = 'Q' | 'E' << 8 | 'D' << 16 | '\0' << 24,
 | 
			
		||||
 | 
			
		||||
    /* The image supports a backing file */
 | 
			
		||||
    QED_F_BACKING_FILE = 0x01,
 | 
			
		||||
 | 
			
		||||
    /* The image needs a consistency check before use */
 | 
			
		||||
    QED_F_NEED_CHECK = 0x02,
 | 
			
		||||
 | 
			
		||||
    /* The backing file format must not be probed, treat as raw image */
 | 
			
		||||
    QED_F_BACKING_FORMAT_NO_PROBE = 0x04,
 | 
			
		||||
 | 
			
		||||
    /* Feature bits must be used when the on-disk format changes */
 | 
			
		||||
    QED_FEATURE_MASK = QED_F_BACKING_FILE | /* supported feature bits */
 | 
			
		||||
                       QED_F_NEED_CHECK |
 | 
			
		||||
                       QED_F_BACKING_FORMAT_NO_PROBE,
 | 
			
		||||
    QED_COMPAT_FEATURE_MASK = 0,            /* supported compat feature bits */
 | 
			
		||||
    QED_AUTOCLEAR_FEATURE_MASK = 0,         /* supported autoclear feature bits */
 | 
			
		||||
 | 
			
		||||
    /* Data is stored in groups of sectors called clusters.  Cluster size must
 | 
			
		||||
     * be large to avoid keeping too much metadata.  I/O requests that have
 | 
			
		||||
     * sub-cluster size will require read-modify-write.
 | 
			
		||||
     */
 | 
			
		||||
    QED_MIN_CLUSTER_SIZE = 4 * 1024, /* in bytes */
 | 
			
		||||
    QED_MAX_CLUSTER_SIZE = 64 * 1024 * 1024,
 | 
			
		||||
    QED_DEFAULT_CLUSTER_SIZE = 64 * 1024,
 | 
			
		||||
 | 
			
		||||
    /* Allocated clusters are tracked using a 2-level pagetable.  Table size is
 | 
			
		||||
     * a multiple of clusters so large maximum image sizes can be supported
 | 
			
		||||
     * without jacking up the cluster size too much.
 | 
			
		||||
     */
 | 
			
		||||
    QED_MIN_TABLE_SIZE = 1,        /* in clusters */
 | 
			
		||||
    QED_MAX_TABLE_SIZE = 16,
 | 
			
		||||
    QED_DEFAULT_TABLE_SIZE = 4,
 | 
			
		||||
 | 
			
		||||
    /* Delay to flush and clean image after last allocating write completes */
 | 
			
		||||
    QED_NEED_CHECK_TIMEOUT = 5,    /* in seconds */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t magic;                 /* QED\0 */
 | 
			
		||||
 | 
			
		||||
    uint32_t cluster_size;          /* in bytes */
 | 
			
		||||
    uint32_t table_size;            /* for L1 and L2 tables, in clusters */
 | 
			
		||||
    uint32_t header_size;           /* in clusters */
 | 
			
		||||
 | 
			
		||||
    uint64_t features;              /* format feature bits */
 | 
			
		||||
    uint64_t compat_features;       /* compatible feature bits */
 | 
			
		||||
    uint64_t autoclear_features;    /* self-resetting feature bits */
 | 
			
		||||
 | 
			
		||||
    uint64_t l1_table_offset;       /* in bytes */
 | 
			
		||||
    uint64_t image_size;            /* total logical image size, in bytes */
 | 
			
		||||
 | 
			
		||||
    /* if (features & QED_F_BACKING_FILE) */
 | 
			
		||||
    uint32_t backing_filename_offset; /* in bytes from start of header */
 | 
			
		||||
    uint32_t backing_filename_size;   /* in bytes */
 | 
			
		||||
} QEDHeader;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint64_t offsets[0];            /* in bytes */
 | 
			
		||||
} QEDTable;
 | 
			
		||||
 | 
			
		||||
/* The L2 cache is a simple write-through cache for L2 structures */
 | 
			
		||||
typedef struct CachedL2Table {
 | 
			
		||||
    QEDTable *table;
 | 
			
		||||
    uint64_t offset;    /* offset=0 indicates an invalidate entry */
 | 
			
		||||
    QTAILQ_ENTRY(CachedL2Table) node;
 | 
			
		||||
    int ref;
 | 
			
		||||
} CachedL2Table;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    QTAILQ_HEAD(, CachedL2Table) entries;
 | 
			
		||||
    unsigned int n_entries;
 | 
			
		||||
} L2TableCache;
 | 
			
		||||
 | 
			
		||||
typedef struct QEDRequest {
 | 
			
		||||
    CachedL2Table *l2_table;
 | 
			
		||||
} QEDRequest;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    QED_AIOCB_WRITE = 0x0001,       /* read or write? */
 | 
			
		||||
    QED_AIOCB_ZERO  = 0x0002,       /* zero write, used with QED_AIOCB_WRITE */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct QEDAIOCB {
 | 
			
		||||
    BlockDriverAIOCB common;
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
    int bh_ret;                     /* final return status for completion bh */
 | 
			
		||||
    QSIMPLEQ_ENTRY(QEDAIOCB) next;  /* next request */
 | 
			
		||||
    int flags;                      /* QED_AIOCB_* bits ORed together */
 | 
			
		||||
    bool *finished;                 /* signal for cancel completion */
 | 
			
		||||
    uint64_t end_pos;               /* request end on block device, in bytes */
 | 
			
		||||
 | 
			
		||||
    /* User scatter-gather list */
 | 
			
		||||
    QEMUIOVector *qiov;
 | 
			
		||||
    size_t qiov_offset;             /* byte count already processed */
 | 
			
		||||
 | 
			
		||||
    /* Current cluster scatter-gather list */
 | 
			
		||||
    QEMUIOVector cur_qiov;
 | 
			
		||||
    uint64_t cur_pos;               /* position on block device, in bytes */
 | 
			
		||||
    uint64_t cur_cluster;           /* cluster offset in image file */
 | 
			
		||||
    unsigned int cur_nclusters;     /* number of clusters being accessed */
 | 
			
		||||
    int find_cluster_ret;           /* used for L1/L2 update */
 | 
			
		||||
 | 
			
		||||
    QEDRequest request;
 | 
			
		||||
} QEDAIOCB;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    BlockDriverState *bs;           /* device */
 | 
			
		||||
    uint64_t file_size;             /* length of image file, in bytes */
 | 
			
		||||
 | 
			
		||||
    QEDHeader header;               /* always cpu-endian */
 | 
			
		||||
    QEDTable *l1_table;
 | 
			
		||||
    L2TableCache l2_cache;          /* l2 table cache */
 | 
			
		||||
    uint32_t table_nelems;
 | 
			
		||||
    uint32_t l1_shift;
 | 
			
		||||
    uint32_t l2_shift;
 | 
			
		||||
    uint32_t l2_mask;
 | 
			
		||||
 | 
			
		||||
    /* Allocating write request queue */
 | 
			
		||||
    QSIMPLEQ_HEAD(, QEDAIOCB) allocating_write_reqs;
 | 
			
		||||
    bool allocating_write_reqs_plugged;
 | 
			
		||||
 | 
			
		||||
    /* Periodic flush and clear need check flag */
 | 
			
		||||
    QEMUTimer *need_check_timer;
 | 
			
		||||
} BDRVQEDState;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    QED_CLUSTER_FOUND,         /* cluster found */
 | 
			
		||||
    QED_CLUSTER_ZERO,          /* zero cluster found */
 | 
			
		||||
    QED_CLUSTER_L2,            /* cluster missing in L2 */
 | 
			
		||||
    QED_CLUSTER_L1,            /* cluster missing in L1 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * qed_find_cluster() completion callback
 | 
			
		||||
 *
 | 
			
		||||
 * @opaque:     User data for completion callback
 | 
			
		||||
 * @ret:        QED_CLUSTER_FOUND   Success
 | 
			
		||||
 *              QED_CLUSTER_L2      Data cluster unallocated in L2
 | 
			
		||||
 *              QED_CLUSTER_L1      L2 unallocated in L1
 | 
			
		||||
 *              -errno              POSIX error occurred
 | 
			
		||||
 * @offset:     Data cluster offset
 | 
			
		||||
 * @len:        Contiguous bytes starting from cluster offset
 | 
			
		||||
 *
 | 
			
		||||
 * This function is invoked when qed_find_cluster() completes.
 | 
			
		||||
 *
 | 
			
		||||
 * On success ret is QED_CLUSTER_FOUND and offset/len are a contiguous range
 | 
			
		||||
 * in the image file.
 | 
			
		||||
 *
 | 
			
		||||
 * On failure ret is QED_CLUSTER_L2 or QED_CLUSTER_L1 for missing L2 or L1
 | 
			
		||||
 * table offset, respectively.  len is number of contiguous unallocated bytes.
 | 
			
		||||
 */
 | 
			
		||||
typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t len);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generic callback for chaining async callbacks
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    BlockDriverCompletionFunc *cb;
 | 
			
		||||
    void *opaque;
 | 
			
		||||
} GenericCB;
 | 
			
		||||
 | 
			
		||||
void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque);
 | 
			
		||||
void gencb_complete(void *opaque, int ret);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * L2 cache functions
 | 
			
		||||
 */
 | 
			
		||||
void qed_init_l2_cache(L2TableCache *l2_cache);
 | 
			
		||||
void qed_free_l2_cache(L2TableCache *l2_cache);
 | 
			
		||||
CachedL2Table *qed_alloc_l2_cache_entry(L2TableCache *l2_cache);
 | 
			
		||||
void qed_unref_l2_cache_entry(CachedL2Table *entry);
 | 
			
		||||
CachedL2Table *qed_find_l2_cache_entry(L2TableCache *l2_cache, uint64_t offset);
 | 
			
		||||
void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Table I/O functions
 | 
			
		||||
 */
 | 
			
		||||
int qed_read_l1_table_sync(BDRVQEDState *s);
 | 
			
		||||
void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
 | 
			
		||||
                        BlockDriverCompletionFunc *cb, void *opaque);
 | 
			
		||||
int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
 | 
			
		||||
                            unsigned int n);
 | 
			
		||||
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 | 
			
		||||
                           uint64_t offset);
 | 
			
		||||
void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
 | 
			
		||||
                       BlockDriverCompletionFunc *cb, void *opaque);
 | 
			
		||||
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
 | 
			
		||||
                        unsigned int index, unsigned int n, bool flush,
 | 
			
		||||
                        BlockDriverCompletionFunc *cb, void *opaque);
 | 
			
		||||
int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 | 
			
		||||
                            unsigned int index, unsigned int n, bool flush);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cluster functions
 | 
			
		||||
 */
 | 
			
		||||
void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
 | 
			
		||||
                      size_t len, QEDFindClusterFunc *cb, void *opaque);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Consistency check
 | 
			
		||||
 */
 | 
			
		||||
int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix);
 | 
			
		||||
 | 
			
		||||
QEDTable *qed_alloc_table(BDRVQEDState *s);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Round down to the start of a cluster
 | 
			
		||||
 */
 | 
			
		||||
static inline uint64_t qed_start_of_cluster(BDRVQEDState *s, uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    return offset & ~(uint64_t)(s->header.cluster_size - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint64_t qed_offset_into_cluster(BDRVQEDState *s, uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    return offset & (s->header.cluster_size - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint64_t qed_bytes_to_clusters(BDRVQEDState *s, uint64_t bytes)
 | 
			
		||||
{
 | 
			
		||||
    return qed_start_of_cluster(s, bytes + (s->header.cluster_size - 1)) /
 | 
			
		||||
           (s->header.cluster_size - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int qed_l1_index(BDRVQEDState *s, uint64_t pos)
 | 
			
		||||
{
 | 
			
		||||
    return pos >> s->l1_shift;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int qed_l2_index(BDRVQEDState *s, uint64_t pos)
 | 
			
		||||
{
 | 
			
		||||
    return (pos >> s->l2_shift) & s->l2_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test if a cluster offset is valid
 | 
			
		||||
 */
 | 
			
		||||
static inline bool qed_check_cluster_offset(BDRVQEDState *s, uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t header_size = (uint64_t)s->header.header_size *
 | 
			
		||||
                           s->header.cluster_size;
 | 
			
		||||
 | 
			
		||||
    if (offset & (s->header.cluster_size - 1)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return offset >= header_size && offset < s->file_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test if a table offset is valid
 | 
			
		||||
 */
 | 
			
		||||
static inline bool qed_check_table_offset(BDRVQEDState *s, uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t end_offset = offset + (s->header.table_size - 1) *
 | 
			
		||||
                          s->header.cluster_size;
 | 
			
		||||
 | 
			
		||||
    /* Overflow check */
 | 
			
		||||
    if (end_offset <= offset) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return qed_check_cluster_offset(s, offset) &&
 | 
			
		||||
           qed_check_cluster_offset(s, end_offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool qed_offset_is_cluster_aligned(BDRVQEDState *s,
 | 
			
		||||
                                                 uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    if (qed_offset_into_cluster(s, offset)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool qed_offset_is_unalloc_cluster(uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    if (offset == 0) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool qed_offset_is_zero_cluster(uint64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    if (offset == 1) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* BLOCK_QED_H */
 | 
			
		||||
@@ -9,8 +9,6 @@
 | 
			
		||||
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
			
		||||
 * the COPYING file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributions after 2012-01-13 are licensed under the terms of the
 | 
			
		||||
 * GNU GPL, version 2 or (at your option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef QEMU_RAW_POSIX_AIO_H
 | 
			
		||||
#define QEMU_RAW_POSIX_AIO_H
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -41,7 +41,6 @@ typedef struct BDRVRawState {
 | 
			
		||||
int qemu_ftruncate64(int fd, int64_t length)
 | 
			
		||||
{
 | 
			
		||||
    LARGE_INTEGER li;
 | 
			
		||||
    DWORD dw;
 | 
			
		||||
    LONG high;
 | 
			
		||||
    HANDLE h;
 | 
			
		||||
    BOOL res;
 | 
			
		||||
@@ -54,15 +53,12 @@ int qemu_ftruncate64(int fd, int64_t length)
 | 
			
		||||
    /* get current position, ftruncate do not change position */
 | 
			
		||||
    li.HighPart = 0;
 | 
			
		||||
    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
 | 
			
		||||
    if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
 | 
			
		||||
    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
 | 
			
		||||
	return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    high = length >> 32;
 | 
			
		||||
    dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN);
 | 
			
		||||
    if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
 | 
			
		||||
    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
 | 
			
		||||
	return -1;
 | 
			
		||||
    }
 | 
			
		||||
    res = SetEndOfFile(h);
 | 
			
		||||
 | 
			
		||||
    /* back to old position */
 | 
			
		||||
@@ -80,25 +76,29 @@ static int set_sparse(int fd)
 | 
			
		||||
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRawState *s = bs->opaque;
 | 
			
		||||
    int access_flags;
 | 
			
		||||
    int access_flags, create_flags;
 | 
			
		||||
    DWORD overlapped;
 | 
			
		||||
 | 
			
		||||
    s->type = FTYPE_FILE;
 | 
			
		||||
 | 
			
		||||
    if (flags & BDRV_O_RDWR) {
 | 
			
		||||
    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
 | 
			
		||||
        access_flags = GENERIC_READ | GENERIC_WRITE;
 | 
			
		||||
    } else {
 | 
			
		||||
        access_flags = GENERIC_READ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (flags & BDRV_O_CREAT) {
 | 
			
		||||
        create_flags = CREATE_ALWAYS;
 | 
			
		||||
    } else {
 | 
			
		||||
        create_flags = OPEN_EXISTING;
 | 
			
		||||
    }
 | 
			
		||||
    overlapped = FILE_ATTRIBUTE_NORMAL;
 | 
			
		||||
    if (flags & BDRV_O_NOCACHE)
 | 
			
		||||
        overlapped |= FILE_FLAG_NO_BUFFERING;
 | 
			
		||||
    if (!(flags & BDRV_O_CACHE_WB))
 | 
			
		||||
    if ((flags & BDRV_O_NOCACHE))
 | 
			
		||||
        overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
 | 
			
		||||
    else if (!(flags & BDRV_O_CACHE_WB))
 | 
			
		||||
        overlapped |= FILE_FLAG_WRITE_THROUGH;
 | 
			
		||||
    s->hfile = CreateFile(filename, access_flags,
 | 
			
		||||
                          FILE_SHARE_READ, NULL,
 | 
			
		||||
                          OPEN_EXISTING, overlapped, NULL);
 | 
			
		||||
                          create_flags, overlapped, NULL);
 | 
			
		||||
    if (s->hfile == INVALID_HANDLE_VALUE) {
 | 
			
		||||
        int err = GetLastError();
 | 
			
		||||
 | 
			
		||||
@@ -151,17 +151,10 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
    return ret_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_flush(BlockDriverState *bs)
 | 
			
		||||
static void raw_flush(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRawState *s = bs->opaque;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    ret = FlushFileBuffers(s->hfile);
 | 
			
		||||
    if (ret == 0) {
 | 
			
		||||
        return -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
    FlushFileBuffers(s->hfile);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void raw_close(BlockDriverState *bs)
 | 
			
		||||
@@ -217,31 +210,6 @@ static int64_t raw_getlength(BlockDriverState *bs)
 | 
			
		||||
    return l.QuadPart;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
 | 
			
		||||
                                              DWORD * high);
 | 
			
		||||
    get_compressed_t get_compressed;
 | 
			
		||||
    struct _stati64 st;
 | 
			
		||||
    const char *filename = bs->filename;
 | 
			
		||||
    /* WinNT support GetCompressedFileSize to determine allocate size */
 | 
			
		||||
    get_compressed =
 | 
			
		||||
        (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
 | 
			
		||||
                                            "GetCompressedFileSizeA");
 | 
			
		||||
    if (get_compressed) {
 | 
			
		||||
        DWORD high, low;
 | 
			
		||||
        low = get_compressed(filename, &high);
 | 
			
		||||
        if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
 | 
			
		||||
            return (((int64_t) high) << 32) + low;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (_stati64(filename, &st) < 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return st.st_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
{
 | 
			
		||||
    int fd;
 | 
			
		||||
@@ -274,22 +242,17 @@ static QEMUOptionParameter raw_create_options[] = {
 | 
			
		||||
    { NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_file = {
 | 
			
		||||
    .format_name	= "file",
 | 
			
		||||
    .protocol_name	= "file",
 | 
			
		||||
static BlockDriver bdrv_raw = {
 | 
			
		||||
    .format_name	= "raw",
 | 
			
		||||
    .instance_size	= sizeof(BDRVRawState),
 | 
			
		||||
    .bdrv_file_open	= raw_open,
 | 
			
		||||
    .bdrv_open		= raw_open,
 | 
			
		||||
    .bdrv_close		= raw_close,
 | 
			
		||||
    .bdrv_create	= raw_create,
 | 
			
		||||
 | 
			
		||||
    .bdrv_flush		= raw_flush,
 | 
			
		||||
    .bdrv_read		= raw_read,
 | 
			
		||||
    .bdrv_write		= raw_write,
 | 
			
		||||
    .bdrv_co_flush_to_disk  = raw_flush,
 | 
			
		||||
 | 
			
		||||
    .bdrv_truncate	= raw_truncate,
 | 
			
		||||
    .bdrv_getlength	= raw_getlength,
 | 
			
		||||
    .bdrv_get_allocated_file_size
 | 
			
		||||
                        = raw_get_allocated_file_size,
 | 
			
		||||
 | 
			
		||||
    .create_options = raw_create_options,
 | 
			
		||||
};
 | 
			
		||||
@@ -374,7 +337,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
    }
 | 
			
		||||
    s->type = find_device_type(bs, filename);
 | 
			
		||||
 | 
			
		||||
    if (flags & BDRV_O_RDWR) {
 | 
			
		||||
    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
 | 
			
		||||
        access_flags = GENERIC_READ | GENERIC_WRITE;
 | 
			
		||||
    } else {
 | 
			
		||||
        access_flags = GENERIC_READ;
 | 
			
		||||
@@ -382,9 +345,9 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
    create_flags = OPEN_EXISTING;
 | 
			
		||||
 | 
			
		||||
    overlapped = FILE_ATTRIBUTE_NORMAL;
 | 
			
		||||
    if (flags & BDRV_O_NOCACHE)
 | 
			
		||||
        overlapped |= FILE_FLAG_NO_BUFFERING;
 | 
			
		||||
    if (!(flags & BDRV_O_CACHE_WB))
 | 
			
		||||
    if ((flags & BDRV_O_NOCACHE))
 | 
			
		||||
        overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
 | 
			
		||||
    else if (!(flags & BDRV_O_CACHE_WB))
 | 
			
		||||
        overlapped |= FILE_FLAG_WRITE_THROUGH;
 | 
			
		||||
    s->hfile = CreateFile(filename, access_flags,
 | 
			
		||||
                          FILE_SHARE_READ, NULL,
 | 
			
		||||
@@ -399,33 +362,58 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int hdev_has_zero_init(BlockDriverState *bs)
 | 
			
		||||
#if 0
 | 
			
		||||
/***********************************************/
 | 
			
		||||
/* removable device additional commands */
 | 
			
		||||
 | 
			
		||||
static int raw_is_inserted(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    return 0;
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_media_changed(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    return -ENOTSUP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_eject(BlockDriverState *bs, int eject_flag)
 | 
			
		||||
{
 | 
			
		||||
    DWORD ret_count;
 | 
			
		||||
 | 
			
		||||
    if (s->type == FTYPE_FILE)
 | 
			
		||||
        return -ENOTSUP;
 | 
			
		||||
    if (eject_flag) {
 | 
			
		||||
        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
 | 
			
		||||
                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
 | 
			
		||||
    } else {
 | 
			
		||||
        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
 | 
			
		||||
                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_set_locked(BlockDriverState *bs, int locked)
 | 
			
		||||
{
 | 
			
		||||
    return -ENOTSUP;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_host_device = {
 | 
			
		||||
    .format_name	= "host_device",
 | 
			
		||||
    .protocol_name	= "host_device",
 | 
			
		||||
    .instance_size	= sizeof(BDRVRawState),
 | 
			
		||||
    .bdrv_probe_device	= hdev_probe_device,
 | 
			
		||||
    .bdrv_file_open	= hdev_open,
 | 
			
		||||
    .bdrv_open		= hdev_open,
 | 
			
		||||
    .bdrv_close		= raw_close,
 | 
			
		||||
    .bdrv_has_zero_init = hdev_has_zero_init,
 | 
			
		||||
    .bdrv_flush		= raw_flush,
 | 
			
		||||
 | 
			
		||||
    .bdrv_read		= raw_read,
 | 
			
		||||
    .bdrv_write	        = raw_write,
 | 
			
		||||
    .bdrv_co_flush_to_disk  = raw_flush,
 | 
			
		||||
 | 
			
		||||
    .bdrv_getlength	= raw_getlength,
 | 
			
		||||
    .bdrv_get_allocated_file_size
 | 
			
		||||
                        = raw_get_allocated_file_size,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void bdrv_file_init(void)
 | 
			
		||||
static void bdrv_raw_init(void)
 | 
			
		||||
{
 | 
			
		||||
    bdrv_register(&bdrv_file);
 | 
			
		||||
    bdrv_register(&bdrv_raw);
 | 
			
		||||
    bdrv_register(&bdrv_host_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
block_init(bdrv_file_init);
 | 
			
		||||
block_init(bdrv_raw_init);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										135
									
								
								block/raw.c
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								block/raw.c
									
									
									
									
									
								
							@@ -1,135 +0,0 @@
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
#include "module.h"
 | 
			
		||||
 | 
			
		||||
static int raw_open(BlockDriverState *bs, int flags)
 | 
			
		||||
{
 | 
			
		||||
    bs->sg = bs->file->sg;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                     int nb_sectors, QEMUIOVector *qiov)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_co_readv(bs->file, sector_num, nb_sectors, qiov);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
 | 
			
		||||
                                      int nb_sectors, QEMUIOVector *qiov)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void raw_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t raw_getlength(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_getlength(bs->file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_truncate(bs->file, offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
   return 1; /* everything can be opened as raw image */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int coroutine_fn raw_co_discard(BlockDriverState *bs,
 | 
			
		||||
                                       int64_t sector_num, int nb_sectors)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_co_discard(bs->file, sector_num, nb_sectors);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_is_inserted(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_is_inserted(bs->file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_media_changed(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_media_changed(bs->file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void raw_eject(BlockDriverState *bs, bool eject_flag)
 | 
			
		||||
{
 | 
			
		||||
    bdrv_eject(bs->file, eject_flag);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void raw_lock_medium(BlockDriverState *bs, bool locked)
 | 
			
		||||
{
 | 
			
		||||
    bdrv_lock_medium(bs->file, locked);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 | 
			
		||||
{
 | 
			
		||||
   return bdrv_ioctl(bs->file, req, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
 | 
			
		||||
        unsigned long int req, void *buf,
 | 
			
		||||
        BlockDriverCompletionFunc *cb, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
   return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int raw_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_create_file(filename, options);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QEMUOptionParameter raw_create_options[] = {
 | 
			
		||||
    {
 | 
			
		||||
        .name = BLOCK_OPT_SIZE,
 | 
			
		||||
        .type = OPT_SIZE,
 | 
			
		||||
        .help = "Virtual disk size"
 | 
			
		||||
    },
 | 
			
		||||
    { NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int raw_has_zero_init(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    return bdrv_has_zero_init(bs->file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_raw = {
 | 
			
		||||
    .format_name        = "raw",
 | 
			
		||||
 | 
			
		||||
    /* It's really 0, but we need to make g_malloc() happy */
 | 
			
		||||
    .instance_size      = 1,
 | 
			
		||||
 | 
			
		||||
    .bdrv_open          = raw_open,
 | 
			
		||||
    .bdrv_close         = raw_close,
 | 
			
		||||
 | 
			
		||||
    .bdrv_co_readv          = raw_co_readv,
 | 
			
		||||
    .bdrv_co_writev         = raw_co_writev,
 | 
			
		||||
    .bdrv_co_discard        = raw_co_discard,
 | 
			
		||||
 | 
			
		||||
    .bdrv_probe         = raw_probe,
 | 
			
		||||
    .bdrv_getlength     = raw_getlength,
 | 
			
		||||
    .bdrv_truncate      = raw_truncate,
 | 
			
		||||
 | 
			
		||||
    .bdrv_is_inserted   = raw_is_inserted,
 | 
			
		||||
    .bdrv_media_changed = raw_media_changed,
 | 
			
		||||
    .bdrv_eject         = raw_eject,
 | 
			
		||||
    .bdrv_lock_medium   = raw_lock_medium,
 | 
			
		||||
 | 
			
		||||
    .bdrv_ioctl         = raw_ioctl,
 | 
			
		||||
    .bdrv_aio_ioctl     = raw_aio_ioctl,
 | 
			
		||||
 | 
			
		||||
    .bdrv_create        = raw_create,
 | 
			
		||||
    .create_options     = raw_create_options,
 | 
			
		||||
    .bdrv_has_zero_init = raw_has_zero_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void bdrv_raw_init(void)
 | 
			
		||||
{
 | 
			
		||||
    bdrv_register(&bdrv_raw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
block_init(bdrv_raw_init);
 | 
			
		||||
							
								
								
									
										894
									
								
								block/rbd.c
									
									
									
									
									
								
							
							
						
						
									
										894
									
								
								block/rbd.c
									
									
									
									
									
								
							@@ -1,894 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * QEMU Block driver for RADOS (Ceph)
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2010-2011 Christian Brunner <chb@muc.de>,
 | 
			
		||||
 *                         Josh Durgin <josh.durgin@dreamhost.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
			
		||||
 * the COPYING file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributions after 2012-01-13 are licensed under the terms of the
 | 
			
		||||
 * GNU GPL, version 2 or (at your option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "qemu-error.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
 | 
			
		||||
#include <rbd/librbd.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * When specifying the image filename use:
 | 
			
		||||
 *
 | 
			
		||||
 * rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]]
 | 
			
		||||
 *
 | 
			
		||||
 * poolname must be the name of an existing rados pool.
 | 
			
		||||
 *
 | 
			
		||||
 * devicename is the name of the rbd image.
 | 
			
		||||
 *
 | 
			
		||||
 * Each option given is used to configure rados, and may be any valid
 | 
			
		||||
 * Ceph option, "id", or "conf".
 | 
			
		||||
 *
 | 
			
		||||
 * The "id" option indicates what user we should authenticate as to
 | 
			
		||||
 * the Ceph cluster.  If it is excluded we will use the Ceph default
 | 
			
		||||
 * (normally 'admin').
 | 
			
		||||
 *
 | 
			
		||||
 * The "conf" option specifies a Ceph configuration file to read.  If
 | 
			
		||||
 * it is not specified, we will read from the default Ceph locations
 | 
			
		||||
 * (e.g., /etc/ceph/ceph.conf).  To avoid reading _any_ configuration
 | 
			
		||||
 * file, specify conf=/dev/null.
 | 
			
		||||
 *
 | 
			
		||||
 * Configuration values containing :, @, or = can be escaped with a
 | 
			
		||||
 * leading "\".
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
 | 
			
		||||
 | 
			
		||||
#define RBD_MAX_CONF_NAME_SIZE 128
 | 
			
		||||
#define RBD_MAX_CONF_VAL_SIZE 512
 | 
			
		||||
#define RBD_MAX_CONF_SIZE 1024
 | 
			
		||||
#define RBD_MAX_POOL_NAME_SIZE 128
 | 
			
		||||
#define RBD_MAX_SNAP_NAME_SIZE 128
 | 
			
		||||
#define RBD_MAX_SNAPS 100
 | 
			
		||||
 | 
			
		||||
typedef struct RBDAIOCB {
 | 
			
		||||
    BlockDriverAIOCB common;
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
    int ret;
 | 
			
		||||
    QEMUIOVector *qiov;
 | 
			
		||||
    char *bounce;
 | 
			
		||||
    int write;
 | 
			
		||||
    int64_t sector_num;
 | 
			
		||||
    int error;
 | 
			
		||||
    struct BDRVRBDState *s;
 | 
			
		||||
    int cancelled;
 | 
			
		||||
} RBDAIOCB;
 | 
			
		||||
 | 
			
		||||
typedef struct RADOSCB {
 | 
			
		||||
    int rcbid;
 | 
			
		||||
    RBDAIOCB *acb;
 | 
			
		||||
    struct BDRVRBDState *s;
 | 
			
		||||
    int done;
 | 
			
		||||
    int64_t size;
 | 
			
		||||
    char *buf;
 | 
			
		||||
    int ret;
 | 
			
		||||
} RADOSCB;
 | 
			
		||||
 | 
			
		||||
#define RBD_FD_READ 0
 | 
			
		||||
#define RBD_FD_WRITE 1
 | 
			
		||||
 | 
			
		||||
typedef struct BDRVRBDState {
 | 
			
		||||
    int fds[2];
 | 
			
		||||
    rados_t cluster;
 | 
			
		||||
    rados_ioctx_t io_ctx;
 | 
			
		||||
    rbd_image_t image;
 | 
			
		||||
    char name[RBD_MAX_IMAGE_NAME_SIZE];
 | 
			
		||||
    int qemu_aio_count;
 | 
			
		||||
    char *snap;
 | 
			
		||||
    int event_reader_pos;
 | 
			
		||||
    RADOSCB *event_rcb;
 | 
			
		||||
} BDRVRBDState;
 | 
			
		||||
 | 
			
		||||
static void rbd_aio_bh_cb(void *opaque);
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_next_tok(char *dst, int dst_len,
 | 
			
		||||
                             char *src, char delim,
 | 
			
		||||
                             const char *name,
 | 
			
		||||
                             char **p)
 | 
			
		||||
{
 | 
			
		||||
    int l;
 | 
			
		||||
    char *end;
 | 
			
		||||
 | 
			
		||||
    *p = NULL;
 | 
			
		||||
 | 
			
		||||
    if (delim != '\0') {
 | 
			
		||||
        for (end = src; *end; ++end) {
 | 
			
		||||
            if (*end == delim) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            if (*end == '\\' && end[1] != '\0') {
 | 
			
		||||
                end++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (*end == delim) {
 | 
			
		||||
            *p = end + 1;
 | 
			
		||||
            *end = '\0';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    l = strlen(src);
 | 
			
		||||
    if (l >= dst_len) {
 | 
			
		||||
        error_report("%s too long", name);
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    } else if (l == 0) {
 | 
			
		||||
        error_report("%s too short", name);
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pstrcpy(dst, dst_len, src);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qemu_rbd_unescape(char *src)
 | 
			
		||||
{
 | 
			
		||||
    char *p;
 | 
			
		||||
 | 
			
		||||
    for (p = src; *src; ++src, ++p) {
 | 
			
		||||
        if (*src == '\\' && src[1] != '\0') {
 | 
			
		||||
            src++;
 | 
			
		||||
        }
 | 
			
		||||
        *p = *src;
 | 
			
		||||
    }
 | 
			
		||||
    *p = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    const char *start;
 | 
			
		||||
    char *p, *buf;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (!strstart(filename, "rbd:", &start)) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buf = g_strdup(start);
 | 
			
		||||
    p = buf;
 | 
			
		||||
    *snap = '\0';
 | 
			
		||||
    *conf = '\0';
 | 
			
		||||
 | 
			
		||||
    ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
 | 
			
		||||
    if (ret < 0 || !p) {
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    qemu_rbd_unescape(pool);
 | 
			
		||||
 | 
			
		||||
    if (strchr(p, '@')) {
 | 
			
		||||
        ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            goto done;
 | 
			
		||||
        }
 | 
			
		||||
        ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
 | 
			
		||||
        qemu_rbd_unescape(snap);
 | 
			
		||||
    } else {
 | 
			
		||||
        ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
 | 
			
		||||
    }
 | 
			
		||||
    qemu_rbd_unescape(name);
 | 
			
		||||
    if (ret < 0 || !p) {
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p);
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
    g_free(buf);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
 | 
			
		||||
{
 | 
			
		||||
    const char *p = conf;
 | 
			
		||||
 | 
			
		||||
    while (*p) {
 | 
			
		||||
        int len;
 | 
			
		||||
        const char *end = strchr(p, ':');
 | 
			
		||||
 | 
			
		||||
        if (end) {
 | 
			
		||||
            len = end - p;
 | 
			
		||||
        } else {
 | 
			
		||||
            len = strlen(p);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (strncmp(p, "id=", 3) == 0) {
 | 
			
		||||
            len -= 3;
 | 
			
		||||
            strncpy(clientname, p + 3, len);
 | 
			
		||||
            clientname[len] = '\0';
 | 
			
		||||
            return clientname;
 | 
			
		||||
        }
 | 
			
		||||
        if (end == NULL) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        p = end + 1;
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
 | 
			
		||||
{
 | 
			
		||||
    char *p, *buf;
 | 
			
		||||
    char name[RBD_MAX_CONF_NAME_SIZE];
 | 
			
		||||
    char value[RBD_MAX_CONF_VAL_SIZE];
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
 | 
			
		||||
    buf = g_strdup(conf);
 | 
			
		||||
    p = buf;
 | 
			
		||||
 | 
			
		||||
    while (p) {
 | 
			
		||||
        ret = qemu_rbd_next_tok(name, sizeof(name), p,
 | 
			
		||||
                                '=', "conf option name", &p);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        qemu_rbd_unescape(name);
 | 
			
		||||
 | 
			
		||||
        if (!p) {
 | 
			
		||||
            error_report("conf option %s has no value", name);
 | 
			
		||||
            ret = -EINVAL;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ret = qemu_rbd_next_tok(value, sizeof(value), p,
 | 
			
		||||
                                ':', "conf option value", &p);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        qemu_rbd_unescape(value);
 | 
			
		||||
 | 
			
		||||
        if (strcmp(name, "conf") == 0) {
 | 
			
		||||
            ret = rados_conf_read_file(cluster, value);
 | 
			
		||||
            if (ret < 0) {
 | 
			
		||||
                error_report("error reading conf file %s", value);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (strcmp(name, "id") == 0) {
 | 
			
		||||
            /* ignore, this is parsed by qemu_rbd_parse_clientname() */
 | 
			
		||||
        } else {
 | 
			
		||||
            ret = rados_conf_set(cluster, name, value);
 | 
			
		||||
            if (ret < 0) {
 | 
			
		||||
                error_report("invalid conf option %s", name);
 | 
			
		||||
                ret = -EINVAL;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_free(buf);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
 | 
			
		||||
{
 | 
			
		||||
    int64_t bytes = 0;
 | 
			
		||||
    int64_t objsize;
 | 
			
		||||
    int obj_order = 0;
 | 
			
		||||
    char pool[RBD_MAX_POOL_NAME_SIZE];
 | 
			
		||||
    char name[RBD_MAX_IMAGE_NAME_SIZE];
 | 
			
		||||
    char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
 | 
			
		||||
    char conf[RBD_MAX_CONF_SIZE];
 | 
			
		||||
    char clientname_buf[RBD_MAX_CONF_SIZE];
 | 
			
		||||
    char *clientname;
 | 
			
		||||
    rados_t cluster;
 | 
			
		||||
    rados_ioctx_t io_ctx;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (qemu_rbd_parsename(filename, pool, sizeof(pool),
 | 
			
		||||
                           snap_buf, sizeof(snap_buf),
 | 
			
		||||
                           name, sizeof(name),
 | 
			
		||||
                           conf, sizeof(conf)) < 0) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Read out options */
 | 
			
		||||
    while (options && options->name) {
 | 
			
		||||
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
 | 
			
		||||
            bytes = options->value.n;
 | 
			
		||||
        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
 | 
			
		||||
            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");
 | 
			
		||||
                    return -EINVAL;
 | 
			
		||||
                }
 | 
			
		||||
                if (objsize < 4096) {
 | 
			
		||||
                    error_report("obj size too small");
 | 
			
		||||
                    return -EINVAL;
 | 
			
		||||
                }
 | 
			
		||||
                obj_order = ffs(objsize) - 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        options++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
 | 
			
		||||
    if (rados_create(&cluster, clientname) < 0) {
 | 
			
		||||
        error_report("error initializing");
 | 
			
		||||
        return -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strstr(conf, "conf=") == NULL) {
 | 
			
		||||
        /* try default location, but ignore failure */
 | 
			
		||||
        rados_conf_read_file(cluster, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conf[0] != '\0' &&
 | 
			
		||||
        qemu_rbd_set_conf(cluster, conf) < 0) {
 | 
			
		||||
        error_report("error setting config options");
 | 
			
		||||
        rados_shutdown(cluster);
 | 
			
		||||
        return -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rados_connect(cluster) < 0) {
 | 
			
		||||
        error_report("error connecting");
 | 
			
		||||
        rados_shutdown(cluster);
 | 
			
		||||
        return -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) {
 | 
			
		||||
        error_report("error opening pool %s", pool);
 | 
			
		||||
        rados_shutdown(cluster);
 | 
			
		||||
        return -EIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = rbd_create(io_ctx, name, bytes, &obj_order);
 | 
			
		||||
    rados_ioctx_destroy(io_ctx);
 | 
			
		||||
    rados_shutdown(cluster);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This aio completion is being called from qemu_rbd_aio_event_reader()
 | 
			
		||||
 * and runs in qemu context. It schedules a bh, but just in case the aio
 | 
			
		||||
 * was not cancelled before.
 | 
			
		||||
 */
 | 
			
		||||
static void qemu_rbd_complete_aio(RADOSCB *rcb)
 | 
			
		||||
{
 | 
			
		||||
    RBDAIOCB *acb = rcb->acb;
 | 
			
		||||
    int64_t r;
 | 
			
		||||
 | 
			
		||||
    if (acb->cancelled) {
 | 
			
		||||
        qemu_vfree(acb->bounce);
 | 
			
		||||
        qemu_aio_release(acb);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    r = rcb->ret;
 | 
			
		||||
 | 
			
		||||
    if (acb->write) {
 | 
			
		||||
        if (r < 0) {
 | 
			
		||||
            acb->ret = r;
 | 
			
		||||
            acb->error = 1;
 | 
			
		||||
        } else if (!acb->error) {
 | 
			
		||||
            acb->ret = rcb->size;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (r < 0) {
 | 
			
		||||
            memset(rcb->buf, 0, rcb->size);
 | 
			
		||||
            acb->ret = r;
 | 
			
		||||
            acb->error = 1;
 | 
			
		||||
        } else if (r < rcb->size) {
 | 
			
		||||
            memset(rcb->buf + r, 0, rcb->size - r);
 | 
			
		||||
            if (!acb->error) {
 | 
			
		||||
                acb->ret = rcb->size;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (!acb->error) {
 | 
			
		||||
            acb->ret = r;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    /* Note that acb->bh can be NULL in case where the aio was cancelled */
 | 
			
		||||
    acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
 | 
			
		||||
    qemu_bh_schedule(acb->bh);
 | 
			
		||||
done:
 | 
			
		||||
    g_free(rcb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * aio fd read handler. It runs in the qemu context and calls the
 | 
			
		||||
 * completion handling of completed rados aio operations.
 | 
			
		||||
 */
 | 
			
		||||
static void qemu_rbd_aio_event_reader(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = opaque;
 | 
			
		||||
 | 
			
		||||
    ssize_t ret;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        char *p = (char *)&s->event_rcb;
 | 
			
		||||
 | 
			
		||||
        /* now read the rcb pointer that was sent from a non qemu thread */
 | 
			
		||||
        ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
 | 
			
		||||
                   sizeof(s->event_rcb) - s->event_reader_pos);
 | 
			
		||||
        if (ret > 0) {
 | 
			
		||||
            s->event_reader_pos += ret;
 | 
			
		||||
            if (s->event_reader_pos == sizeof(s->event_rcb)) {
 | 
			
		||||
                s->event_reader_pos = 0;
 | 
			
		||||
                qemu_rbd_complete_aio(s->event_rcb);
 | 
			
		||||
                s->qemu_aio_count--;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } while (ret < 0 && errno == EINTR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_aio_flush_cb(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = opaque;
 | 
			
		||||
 | 
			
		||||
    return (s->qemu_aio_count > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    char pool[RBD_MAX_POOL_NAME_SIZE];
 | 
			
		||||
    char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
 | 
			
		||||
    char conf[RBD_MAX_CONF_SIZE];
 | 
			
		||||
    char clientname_buf[RBD_MAX_CONF_SIZE];
 | 
			
		||||
    char *clientname;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    if (qemu_rbd_parsename(filename, pool, sizeof(pool),
 | 
			
		||||
                           snap_buf, sizeof(snap_buf),
 | 
			
		||||
                           s->name, sizeof(s->name),
 | 
			
		||||
                           conf, sizeof(conf)) < 0) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
 | 
			
		||||
    r = rados_create(&s->cluster, clientname);
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        error_report("error initializing");
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s->snap = NULL;
 | 
			
		||||
    if (snap_buf[0] != '\0') {
 | 
			
		||||
        s->snap = g_strdup(snap_buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strstr(conf, "conf=") == NULL) {
 | 
			
		||||
        /* try default location, but ignore failure */
 | 
			
		||||
        rados_conf_read_file(s->cluster, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conf[0] != '\0') {
 | 
			
		||||
        r = qemu_rbd_set_conf(s->cluster, conf);
 | 
			
		||||
        if (r < 0) {
 | 
			
		||||
            error_report("error setting config options");
 | 
			
		||||
            goto failed_shutdown;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    r = rados_connect(s->cluster);
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        error_report("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);
 | 
			
		||||
        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);
 | 
			
		||||
        goto failed_open;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bs->read_only = (s->snap != NULL);
 | 
			
		||||
 | 
			
		||||
    s->event_reader_pos = 0;
 | 
			
		||||
    r = qemu_pipe(s->fds);
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        error_report("error opening eventfd");
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
    fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
 | 
			
		||||
    fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
 | 
			
		||||
    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
 | 
			
		||||
                            NULL, qemu_rbd_aio_flush_cb, s);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
failed:
 | 
			
		||||
    rbd_close(s->image);
 | 
			
		||||
failed_open:
 | 
			
		||||
    rados_ioctx_destroy(s->io_ctx);
 | 
			
		||||
failed_shutdown:
 | 
			
		||||
    rados_shutdown(s->cluster);
 | 
			
		||||
    g_free(s->snap);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qemu_rbd_close(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    close(s->fds[0]);
 | 
			
		||||
    close(s->fds[1]);
 | 
			
		||||
    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
    rbd_close(s->image);
 | 
			
		||||
    rados_ioctx_destroy(s->io_ctx);
 | 
			
		||||
    g_free(s->snap);
 | 
			
		||||
    rados_shutdown(s->cluster);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Cancel aio. Since we don't reference acb in a non qemu threads,
 | 
			
		||||
 * it is safe to access it here.
 | 
			
		||||
 */
 | 
			
		||||
static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
 | 
			
		||||
{
 | 
			
		||||
    RBDAIOCB *acb = (RBDAIOCB *) blockacb;
 | 
			
		||||
    acb->cancelled = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static AIOPool rbd_aio_pool = {
 | 
			
		||||
    .aiocb_size = sizeof(RBDAIOCB),
 | 
			
		||||
    .cancel = qemu_rbd_aio_cancel,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_send_pipe(BDRVRBDState *s, RADOSCB *rcb)
 | 
			
		||||
{
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
    while (1) {
 | 
			
		||||
        fd_set wfd;
 | 
			
		||||
        int fd = s->fds[RBD_FD_WRITE];
 | 
			
		||||
 | 
			
		||||
        /* send the op pointer to the qemu thread that is responsible
 | 
			
		||||
           for the aio/op completion. Must do it in a qemu thread context */
 | 
			
		||||
        ret = write(fd, (void *)&rcb, sizeof(rcb));
 | 
			
		||||
        if (ret >= 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (errno == EINTR) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (errno != EAGAIN) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FD_ZERO(&wfd);
 | 
			
		||||
        FD_SET(fd, &wfd);
 | 
			
		||||
        do {
 | 
			
		||||
            ret = select(fd + 1, NULL, &wfd, NULL, NULL);
 | 
			
		||||
        } while (ret < 0 && errno == EINTR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is the callback function for rbd_aio_read and _write
 | 
			
		||||
 *
 | 
			
		||||
 * Note: this function is being called from a non qemu thread so
 | 
			
		||||
 * we need to be careful about what we do here. Generally we only
 | 
			
		||||
 * write to the block notification pipe, and do the rest of the
 | 
			
		||||
 * io completion handling from qemu_rbd_aio_event_reader() which
 | 
			
		||||
 * runs in a qemu context.
 | 
			
		||||
 */
 | 
			
		||||
static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    rcb->ret = rbd_aio_get_return_value(c);
 | 
			
		||||
    rbd_aio_release(c);
 | 
			
		||||
    ret = qemu_rbd_send_pipe(rcb->s, rcb);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        error_report("failed writing to acb->s->fds");
 | 
			
		||||
        g_free(rcb);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Callback when all queued rbd_aio requests are complete */
 | 
			
		||||
 | 
			
		||||
static void rbd_aio_bh_cb(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    RBDAIOCB *acb = opaque;
 | 
			
		||||
 | 
			
		||||
    if (!acb->write) {
 | 
			
		||||
        qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
 | 
			
		||||
    }
 | 
			
		||||
    qemu_vfree(acb->bounce);
 | 
			
		||||
    acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
 | 
			
		||||
    qemu_bh_delete(acb->bh);
 | 
			
		||||
    acb->bh = NULL;
 | 
			
		||||
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
 | 
			
		||||
                                           int64_t sector_num,
 | 
			
		||||
                                           QEMUIOVector *qiov,
 | 
			
		||||
                                           int nb_sectors,
 | 
			
		||||
                                           BlockDriverCompletionFunc *cb,
 | 
			
		||||
                                           void *opaque, int write)
 | 
			
		||||
{
 | 
			
		||||
    RBDAIOCB *acb;
 | 
			
		||||
    RADOSCB *rcb;
 | 
			
		||||
    rbd_completion_t c;
 | 
			
		||||
    int64_t off, size;
 | 
			
		||||
    char *buf;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
 | 
			
		||||
    acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
 | 
			
		||||
    acb->write = write;
 | 
			
		||||
    acb->qiov = qiov;
 | 
			
		||||
    acb->bounce = qemu_blockalign(bs, qiov->size);
 | 
			
		||||
    acb->ret = 0;
 | 
			
		||||
    acb->error = 0;
 | 
			
		||||
    acb->s = s;
 | 
			
		||||
    acb->cancelled = 0;
 | 
			
		||||
    acb->bh = NULL;
 | 
			
		||||
 | 
			
		||||
    if (write) {
 | 
			
		||||
        qemu_iovec_to_buffer(acb->qiov, acb->bounce);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buf = acb->bounce;
 | 
			
		||||
 | 
			
		||||
    off = sector_num * BDRV_SECTOR_SIZE;
 | 
			
		||||
    size = nb_sectors * BDRV_SECTOR_SIZE;
 | 
			
		||||
 | 
			
		||||
    s->qemu_aio_count++; /* All the RADOSCB */
 | 
			
		||||
 | 
			
		||||
    rcb = g_malloc(sizeof(RADOSCB));
 | 
			
		||||
    rcb->done = 0;
 | 
			
		||||
    rcb->acb = acb;
 | 
			
		||||
    rcb->buf = buf;
 | 
			
		||||
    rcb->s = acb->s;
 | 
			
		||||
    rcb->size = size;
 | 
			
		||||
    r = rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (write) {
 | 
			
		||||
        r = rbd_aio_write(s->image, off, size, buf, c);
 | 
			
		||||
    } else {
 | 
			
		||||
        r = rbd_aio_read(s->image, off, size, buf, c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        goto failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return &acb->common;
 | 
			
		||||
 | 
			
		||||
failed:
 | 
			
		||||
    g_free(rcb);
 | 
			
		||||
    s->qemu_aio_count--;
 | 
			
		||||
    qemu_aio_release(acb);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
 | 
			
		||||
                                            int64_t sector_num,
 | 
			
		||||
                                            QEMUIOVector *qiov,
 | 
			
		||||
                                            int nb_sectors,
 | 
			
		||||
                                            BlockDriverCompletionFunc *cb,
 | 
			
		||||
                                            void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
 | 
			
		||||
                                             int64_t sector_num,
 | 
			
		||||
                                             QEMUIOVector *qiov,
 | 
			
		||||
                                             int nb_sectors,
 | 
			
		||||
                                             BlockDriverCompletionFunc *cb,
 | 
			
		||||
                                             void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_co_flush(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
 | 
			
		||||
    /* rbd_flush added in 0.1.1 */
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    return rbd_flush(s->image);
 | 
			
		||||
#else
 | 
			
		||||
    return 0;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    rbd_image_info_t info;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    r = rbd_stat(s->image, &info, sizeof(info));
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bdi->cluster_size = info.obj_size;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int64_t qemu_rbd_getlength(BlockDriverState *bs)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    rbd_image_info_t info;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    r = rbd_stat(s->image, &info, sizeof(info));
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return info.size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    r = rbd_resize(s->image, offset);
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_snap_create(BlockDriverState *bs,
 | 
			
		||||
                                QEMUSnapshotInfo *sn_info)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    if (sn_info->name[0] == '\0') {
 | 
			
		||||
        return -EINVAL; /* we need a name for rbd snapshots */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * rbd snapshots are using the name as the user controlled unique identifier
 | 
			
		||||
     * we can't use the rbd snapid for that purpose, as it can't be set
 | 
			
		||||
     */
 | 
			
		||||
    if (sn_info->id_str[0] != '\0' &&
 | 
			
		||||
        strcmp(sn_info->id_str, sn_info->name) != 0) {
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strlen(sn_info->name) >= sizeof(sn_info->id_str)) {
 | 
			
		||||
        return -ERANGE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    r = rbd_snap_create(s->image, sn_info->name);
 | 
			
		||||
    if (r < 0) {
 | 
			
		||||
        error_report("failed to create snap: %s", strerror(-r));
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_snap_remove(BlockDriverState *bs,
 | 
			
		||||
                                const char *snapshot_name)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    r = rbd_snap_remove(s->image, snapshot_name);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_snap_rollback(BlockDriverState *bs,
 | 
			
		||||
                                  const char *snapshot_name)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    r = rbd_snap_rollback(s->image, snapshot_name);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qemu_rbd_snap_list(BlockDriverState *bs,
 | 
			
		||||
                              QEMUSnapshotInfo **psn_tab)
 | 
			
		||||
{
 | 
			
		||||
    BDRVRBDState *s = bs->opaque;
 | 
			
		||||
    QEMUSnapshotInfo *sn_info, *sn_tab = NULL;
 | 
			
		||||
    int i, snap_count;
 | 
			
		||||
    rbd_snap_info_t *snaps;
 | 
			
		||||
    int max_snaps = RBD_MAX_SNAPS;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        snaps = g_malloc(sizeof(*snaps) * max_snaps);
 | 
			
		||||
        snap_count = rbd_snap_list(s->image, snaps, &max_snaps);
 | 
			
		||||
        if (snap_count < 0) {
 | 
			
		||||
            g_free(snaps);
 | 
			
		||||
        }
 | 
			
		||||
    } while (snap_count == -ERANGE);
 | 
			
		||||
 | 
			
		||||
    if (snap_count <= 0) {
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sn_tab = g_malloc0(snap_count * sizeof(QEMUSnapshotInfo));
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < snap_count; i++) {
 | 
			
		||||
        const char *snap_name = snaps[i].name;
 | 
			
		||||
 | 
			
		||||
        sn_info = sn_tab + i;
 | 
			
		||||
        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), snap_name);
 | 
			
		||||
        pstrcpy(sn_info->name, sizeof(sn_info->name), snap_name);
 | 
			
		||||
 | 
			
		||||
        sn_info->vm_state_size = snaps[i].size;
 | 
			
		||||
        sn_info->date_sec = 0;
 | 
			
		||||
        sn_info->date_nsec = 0;
 | 
			
		||||
        sn_info->vm_clock_nsec = 0;
 | 
			
		||||
    }
 | 
			
		||||
    rbd_snap_list_end(snaps);
 | 
			
		||||
 | 
			
		||||
 done:
 | 
			
		||||
    *psn_tab = sn_tab;
 | 
			
		||||
    return snap_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QEMUOptionParameter qemu_rbd_create_options[] = {
 | 
			
		||||
    {
 | 
			
		||||
     .name = BLOCK_OPT_SIZE,
 | 
			
		||||
     .type = OPT_SIZE,
 | 
			
		||||
     .help = "Virtual disk size"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
     .name = BLOCK_OPT_CLUSTER_SIZE,
 | 
			
		||||
     .type = OPT_SIZE,
 | 
			
		||||
     .help = "RBD object size"
 | 
			
		||||
    },
 | 
			
		||||
    {NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static BlockDriver bdrv_rbd = {
 | 
			
		||||
    .format_name        = "rbd",
 | 
			
		||||
    .instance_size      = sizeof(BDRVRBDState),
 | 
			
		||||
    .bdrv_file_open     = qemu_rbd_open,
 | 
			
		||||
    .bdrv_close         = qemu_rbd_close,
 | 
			
		||||
    .bdrv_create        = qemu_rbd_create,
 | 
			
		||||
    .bdrv_get_info      = qemu_rbd_getinfo,
 | 
			
		||||
    .create_options     = qemu_rbd_create_options,
 | 
			
		||||
    .bdrv_getlength     = qemu_rbd_getlength,
 | 
			
		||||
    .bdrv_truncate      = qemu_rbd_truncate,
 | 
			
		||||
    .protocol_name      = "rbd",
 | 
			
		||||
 | 
			
		||||
    .bdrv_aio_readv         = qemu_rbd_aio_readv,
 | 
			
		||||
    .bdrv_aio_writev        = qemu_rbd_aio_writev,
 | 
			
		||||
    .bdrv_co_flush_to_disk  = qemu_rbd_co_flush,
 | 
			
		||||
 | 
			
		||||
    .bdrv_snapshot_create   = qemu_rbd_snap_create,
 | 
			
		||||
    .bdrv_snapshot_delete   = qemu_rbd_snap_remove,
 | 
			
		||||
    .bdrv_snapshot_list     = qemu_rbd_snap_list,
 | 
			
		||||
    .bdrv_snapshot_goto     = qemu_rbd_snap_rollback,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void bdrv_rbd_init(void)
 | 
			
		||||
{
 | 
			
		||||
    bdrv_register(&bdrv_rbd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
block_init(bdrv_rbd_init);
 | 
			
		||||
							
								
								
									
										2038
									
								
								block/sheepdog.c
									
									
									
									
									
								
							
							
						
						
									
										2038
									
								
								block/sheepdog.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										304
									
								
								block/stream.c
									
									
									
									
									
								
							
							
						
						
									
										304
									
								
								block/stream.c
									
									
									
									
									
								
							@@ -1,304 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Image streaming
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright IBM, Corp. 2011
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
#include "block_int.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    /*
 | 
			
		||||
     * Size of data buffer for populating the image file.  This should be large
 | 
			
		||||
     * enough to process multiple clusters in a single call, so that populating
 | 
			
		||||
     * contiguous regions of the image is efficient.
 | 
			
		||||
     */
 | 
			
		||||
    STREAM_BUFFER_SIZE = 512 * 1024, /* in bytes */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define SLICE_TIME 100000000ULL /* ns */
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int64_t next_slice_time;
 | 
			
		||||
    uint64_t slice_quota;
 | 
			
		||||
    uint64_t dispatched;
 | 
			
		||||
} RateLimit;
 | 
			
		||||
 | 
			
		||||
static int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
 | 
			
		||||
{
 | 
			
		||||
    int64_t delay_ns = 0;
 | 
			
		||||
    int64_t now = qemu_get_clock_ns(rt_clock);
 | 
			
		||||
 | 
			
		||||
    if (limit->next_slice_time < now) {
 | 
			
		||||
        limit->next_slice_time = now + SLICE_TIME;
 | 
			
		||||
        limit->dispatched = 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (limit->dispatched + n > limit->slice_quota) {
 | 
			
		||||
        delay_ns = limit->next_slice_time - now;
 | 
			
		||||
    } else {
 | 
			
		||||
        limit->dispatched += n;
 | 
			
		||||
    }
 | 
			
		||||
    return delay_ns;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ratelimit_set_speed(RateLimit *limit, uint64_t speed)
 | 
			
		||||
{
 | 
			
		||||
    limit->slice_quota = speed / (1000000000ULL / SLICE_TIME);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct StreamBlockJob {
 | 
			
		||||
    BlockJob common;
 | 
			
		||||
    RateLimit limit;
 | 
			
		||||
    BlockDriverState *base;
 | 
			
		||||
    char backing_file_id[1024];
 | 
			
		||||
} StreamBlockJob;
 | 
			
		||||
 | 
			
		||||
static int coroutine_fn stream_populate(BlockDriverState *bs,
 | 
			
		||||
                                        int64_t sector_num, int nb_sectors,
 | 
			
		||||
                                        void *buf)
 | 
			
		||||
{
 | 
			
		||||
    struct iovec iov = {
 | 
			
		||||
        .iov_base = buf,
 | 
			
		||||
        .iov_len  = nb_sectors * BDRV_SECTOR_SIZE,
 | 
			
		||||
    };
 | 
			
		||||
    QEMUIOVector qiov;
 | 
			
		||||
 | 
			
		||||
    qemu_iovec_init_external(&qiov, &iov, 1);
 | 
			
		||||
 | 
			
		||||
    /* Copy-on-read the unallocated clusters */
 | 
			
		||||
    return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
 | 
			
		||||
                                const char *base_id)
 | 
			
		||||
{
 | 
			
		||||
    BlockDriverState *intermediate;
 | 
			
		||||
    intermediate = top->backing_hd;
 | 
			
		||||
 | 
			
		||||
    while (intermediate) {
 | 
			
		||||
        BlockDriverState *unused;
 | 
			
		||||
 | 
			
		||||
        /* reached base */
 | 
			
		||||
        if (intermediate == base) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        unused = intermediate;
 | 
			
		||||
        intermediate = intermediate->backing_hd;
 | 
			
		||||
        unused->backing_hd = NULL;
 | 
			
		||||
        bdrv_delete(unused);
 | 
			
		||||
    }
 | 
			
		||||
    top->backing_hd = base;
 | 
			
		||||
 | 
			
		||||
    pstrcpy(top->backing_file, sizeof(top->backing_file), "");
 | 
			
		||||
    pstrcpy(top->backing_format, sizeof(top->backing_format), "");
 | 
			
		||||
    if (base_id) {
 | 
			
		||||
        pstrcpy(top->backing_file, sizeof(top->backing_file), base_id);
 | 
			
		||||
        if (base->drv) {
 | 
			
		||||
            pstrcpy(top->backing_format, sizeof(top->backing_format),
 | 
			
		||||
                    base->drv->format_name);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Given an image chain: [BASE] -> [INTER1] -> [INTER2] -> [TOP]
 | 
			
		||||
 *
 | 
			
		||||
 * Return true if the given sector is allocated in top.
 | 
			
		||||
 * Return false if the given sector is allocated in intermediate images.
 | 
			
		||||
 * Return true otherwise.
 | 
			
		||||
 *
 | 
			
		||||
 * 'pnum' is set to the number of sectors (including and immediately following
 | 
			
		||||
 *  the specified sector) that are known to be in the same
 | 
			
		||||
 *  allocated/unallocated state.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int coroutine_fn is_allocated_base(BlockDriverState *top,
 | 
			
		||||
                                          BlockDriverState *base,
 | 
			
		||||
                                          int64_t sector_num,
 | 
			
		||||
                                          int nb_sectors, int *pnum)
 | 
			
		||||
{
 | 
			
		||||
    BlockDriverState *intermediate;
 | 
			
		||||
    int ret, n;
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_co_is_allocated(top, sector_num, nb_sectors, &n);
 | 
			
		||||
    if (ret) {
 | 
			
		||||
        *pnum = n;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Is the unallocated chunk [sector_num, n] also
 | 
			
		||||
     * unallocated between base and top?
 | 
			
		||||
     */
 | 
			
		||||
    intermediate = top->backing_hd;
 | 
			
		||||
 | 
			
		||||
    while (intermediate) {
 | 
			
		||||
        int pnum_inter;
 | 
			
		||||
 | 
			
		||||
        /* reached base */
 | 
			
		||||
        if (intermediate == base) {
 | 
			
		||||
            *pnum = n;
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
        ret = bdrv_co_is_allocated(intermediate, sector_num, nb_sectors,
 | 
			
		||||
                                   &pnum_inter);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        } else if (ret) {
 | 
			
		||||
            *pnum = pnum_inter;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * [sector_num, nb_sectors] is unallocated on top but intermediate
 | 
			
		||||
         * might have
 | 
			
		||||
         *
 | 
			
		||||
         * [sector_num+x, nr_sectors] allocated.
 | 
			
		||||
         */
 | 
			
		||||
        if (n > pnum_inter) {
 | 
			
		||||
            n = pnum_inter;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        intermediate = intermediate->backing_hd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void coroutine_fn stream_run(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    StreamBlockJob *s = opaque;
 | 
			
		||||
    BlockDriverState *bs = s->common.bs;
 | 
			
		||||
    BlockDriverState *base = s->base;
 | 
			
		||||
    int64_t sector_num, end;
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
    int n;
 | 
			
		||||
    void *buf;
 | 
			
		||||
 | 
			
		||||
    s->common.len = bdrv_getlength(bs);
 | 
			
		||||
    if (s->common.len < 0) {
 | 
			
		||||
        block_job_complete(&s->common, s->common.len);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    end = s->common.len >> BDRV_SECTOR_BITS;
 | 
			
		||||
    buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE);
 | 
			
		||||
 | 
			
		||||
    /* Turn on copy-on-read for the whole block device so that guest read
 | 
			
		||||
     * requests help us make progress.  Only do this when copying the entire
 | 
			
		||||
     * backing chain since the copy-on-read operation does not take base into
 | 
			
		||||
     * account.
 | 
			
		||||
     */
 | 
			
		||||
    if (!base) {
 | 
			
		||||
        bdrv_enable_copy_on_read(bs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (sector_num = 0; sector_num < end; sector_num += n) {
 | 
			
		||||
retry:
 | 
			
		||||
        if (block_job_is_cancelled(&s->common)) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        s->common.busy = true;
 | 
			
		||||
        if (base) {
 | 
			
		||||
            ret = is_allocated_base(bs, base, sector_num,
 | 
			
		||||
                                    STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
 | 
			
		||||
        } else {
 | 
			
		||||
            ret = bdrv_co_is_allocated(bs, sector_num,
 | 
			
		||||
                                       STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE,
 | 
			
		||||
                                       &n);
 | 
			
		||||
        }
 | 
			
		||||
        trace_stream_one_iteration(s, sector_num, n, ret);
 | 
			
		||||
        if (ret == 0) {
 | 
			
		||||
            if (s->common.speed) {
 | 
			
		||||
                uint64_t delay_ns = ratelimit_calculate_delay(&s->limit, n);
 | 
			
		||||
                if (delay_ns > 0) {
 | 
			
		||||
                    s->common.busy = false;
 | 
			
		||||
                    co_sleep_ns(rt_clock, delay_ns);
 | 
			
		||||
 | 
			
		||||
                    /* Recheck cancellation and that sectors are unallocated */
 | 
			
		||||
                    goto retry;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            ret = stream_populate(bs, sector_num, n, buf);
 | 
			
		||||
        }
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        ret = 0;
 | 
			
		||||
 | 
			
		||||
        /* Publish progress */
 | 
			
		||||
        s->common.offset += n * BDRV_SECTOR_SIZE;
 | 
			
		||||
 | 
			
		||||
        /* Note that even when no rate limit is applied we need to yield
 | 
			
		||||
         * with no pending I/O here so that qemu_aio_flush() returns.
 | 
			
		||||
         */
 | 
			
		||||
        s->common.busy = false;
 | 
			
		||||
        co_sleep_ns(rt_clock, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!base) {
 | 
			
		||||
        bdrv_disable_copy_on_read(bs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) {
 | 
			
		||||
        const char *base_id = NULL;
 | 
			
		||||
        if (base) {
 | 
			
		||||
            base_id = s->backing_file_id;
 | 
			
		||||
        }
 | 
			
		||||
        ret = bdrv_change_backing_file(bs, base_id, NULL);
 | 
			
		||||
        close_unused_images(bs, base, base_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qemu_vfree(buf);
 | 
			
		||||
    block_job_complete(&s->common, ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    StreamBlockJob *s = container_of(job, StreamBlockJob, common);
 | 
			
		||||
 | 
			
		||||
    if (speed < 0) {
 | 
			
		||||
        error_set(errp, QERR_INVALID_PARAMETER, "speed");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BlockJobType stream_job_type = {
 | 
			
		||||
    .instance_size = sizeof(StreamBlockJob),
 | 
			
		||||
    .job_type      = "stream",
 | 
			
		||||
    .set_speed     = stream_set_speed,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void stream_start(BlockDriverState *bs, BlockDriverState *base,
 | 
			
		||||
                  const char *base_id, int64_t speed,
 | 
			
		||||
                  BlockDriverCompletionFunc *cb,
 | 
			
		||||
                  void *opaque, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    StreamBlockJob *s;
 | 
			
		||||
    Coroutine *co;
 | 
			
		||||
 | 
			
		||||
    s = block_job_create(&stream_job_type, bs, speed, cb, opaque, errp);
 | 
			
		||||
    if (!s) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s->base = base;
 | 
			
		||||
    if (base_id) {
 | 
			
		||||
        pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    co = qemu_coroutine_create(stream_run);
 | 
			
		||||
    trace_stream_start(bs, base, s, co, opaque);
 | 
			
		||||
    qemu_coroutine_enter(co, s);
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user