Compare commits
	
		
			341 Commits
		
	
	
		
			v1.2.0-rc1
			...
			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 | 
							
								
								
									
										49
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -2,25 +2,14 @@ config-devices.*
 | 
				
			|||||||
config-all-devices.*
 | 
					config-all-devices.*
 | 
				
			||||||
config-host.*
 | 
					config-host.*
 | 
				
			||||||
config-target.*
 | 
					config-target.*
 | 
				
			||||||
trace.h
 | 
					i386
 | 
				
			||||||
trace.c
 | 
					 | 
				
			||||||
trace-dtrace.h
 | 
					 | 
				
			||||||
trace-dtrace.dtrace
 | 
					 | 
				
			||||||
*-timestamp
 | 
					 | 
				
			||||||
*-softmmu
 | 
					*-softmmu
 | 
				
			||||||
*-darwin-user
 | 
					*-darwin-user
 | 
				
			||||||
*-linux-user
 | 
					*-linux-user
 | 
				
			||||||
*-bsd-user
 | 
					*-bsd-user
 | 
				
			||||||
libdis*
 | 
					 | 
				
			||||||
libhw32
 | 
					libhw32
 | 
				
			||||||
libhw64
 | 
					libhw64
 | 
				
			||||||
libuser
 | 
					libuser
 | 
				
			||||||
linux-headers/asm
 | 
					 | 
				
			||||||
qapi-generated
 | 
					 | 
				
			||||||
qapi-types.[ch]
 | 
					 | 
				
			||||||
qapi-visit.[ch]
 | 
					 | 
				
			||||||
qmp-commands.h
 | 
					 | 
				
			||||||
qmp-marshal.c
 | 
					 | 
				
			||||||
qemu-doc.html
 | 
					qemu-doc.html
 | 
				
			||||||
qemu-tech.html
 | 
					qemu-tech.html
 | 
				
			||||||
qemu-doc.info
 | 
					qemu-doc.info
 | 
				
			||||||
@@ -33,24 +22,11 @@ qemu-img
 | 
				
			|||||||
qemu-nbd
 | 
					qemu-nbd
 | 
				
			||||||
qemu-nbd.8
 | 
					qemu-nbd.8
 | 
				
			||||||
qemu-nbd.pod
 | 
					qemu-nbd.pod
 | 
				
			||||||
qemu-options.def
 | 
					 | 
				
			||||||
qemu-options.texi
 | 
					qemu-options.texi
 | 
				
			||||||
qemu-img-cmds.texi
 | 
					qemu-img-cmds.texi
 | 
				
			||||||
qemu-img-cmds.h
 | 
					qemu-img-cmds.h
 | 
				
			||||||
qemu-io
 | 
					qemu-io
 | 
				
			||||||
qemu-ga
 | 
					 | 
				
			||||||
qemu-bridge-helper
 | 
					 | 
				
			||||||
qemu-monitor.texi
 | 
					qemu-monitor.texi
 | 
				
			||||||
vscclient
 | 
					 | 
				
			||||||
QMP/qmp-commands.txt
 | 
					 | 
				
			||||||
test-coroutine
 | 
					 | 
				
			||||||
test-qmp-input-visitor
 | 
					 | 
				
			||||||
test-qmp-output-visitor
 | 
					 | 
				
			||||||
test-string-input-visitor
 | 
					 | 
				
			||||||
test-string-output-visitor
 | 
					 | 
				
			||||||
test-visitor-serialization
 | 
					 | 
				
			||||||
fsdev/virtfs-proxy-helper.1
 | 
					 | 
				
			||||||
fsdev/virtfs-proxy-helper.pod
 | 
					 | 
				
			||||||
.gdbinit
 | 
					.gdbinit
 | 
				
			||||||
*.a
 | 
					*.a
 | 
				
			||||||
*.aux
 | 
					*.aux
 | 
				
			||||||
@@ -60,38 +36,17 @@ fsdev/virtfs-proxy-helper.pod
 | 
				
			|||||||
*.fn
 | 
					*.fn
 | 
				
			||||||
*.ky
 | 
					*.ky
 | 
				
			||||||
*.log
 | 
					*.log
 | 
				
			||||||
*.pdf
 | 
					 | 
				
			||||||
*.cps
 | 
					 | 
				
			||||||
*.fns
 | 
					 | 
				
			||||||
*.kys
 | 
					 | 
				
			||||||
*.pg
 | 
					*.pg
 | 
				
			||||||
*.pyc
 | 
					 | 
				
			||||||
*.toc
 | 
					*.toc
 | 
				
			||||||
*.tp
 | 
					*.tp
 | 
				
			||||||
*.vr
 | 
					*.vr
 | 
				
			||||||
*.d
 | 
					*.d
 | 
				
			||||||
*.o
 | 
					*.o
 | 
				
			||||||
*.lo
 | 
					 | 
				
			||||||
*.la
 | 
					 | 
				
			||||||
*.pc
 | 
					 | 
				
			||||||
.libs
 | 
					 | 
				
			||||||
*.swp
 | 
					 | 
				
			||||||
*.orig
 | 
					 | 
				
			||||||
.pc
 | 
					.pc
 | 
				
			||||||
patches
 | 
					patches
 | 
				
			||||||
pc-bios/bios-pq/status
 | 
					pc-bios/bios-pq/status
 | 
				
			||||||
pc-bios/vgabios-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.bin
 | 
				
			||||||
pc-bios/optionrom/multiboot.raw
 | 
					pc-bios/optionrom/multiboot.raw
 | 
				
			||||||
pc-bios/optionrom/multiboot.img
 | 
					pc-bios/optionrom/extboot.bin
 | 
				
			||||||
pc-bios/optionrom/kvmvapic.bin
 | 
					 | 
				
			||||||
pc-bios/optionrom/kvmvapic.raw
 | 
					 | 
				
			||||||
pc-bios/optionrom/kvmvapic.img
 | 
					 | 
				
			||||||
.stgit-*
 | 
					.stgit-*
 | 
				
			||||||
cscope.*
 | 
					 | 
				
			||||||
tags
 | 
					 | 
				
			||||||
TAGS
 | 
					 | 
				
			||||||
*~
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -1,21 +1,6 @@
 | 
				
			|||||||
[submodule "roms/vgabios"]
 | 
					[submodule "roms/vgabios"]
 | 
				
			||||||
	path = roms/vgabios
 | 
						path = roms/vgabios
 | 
				
			||||||
	url = git://git.qemu.org/vgabios.git/
 | 
						url = ../vgabios.git
 | 
				
			||||||
[submodule "roms/seabios"]
 | 
					[submodule "roms/seabios"]
 | 
				
			||||||
	path = roms/seabios
 | 
						path = roms/seabios
 | 
				
			||||||
	url = git://git.qemu.org/seabios.git/
 | 
						url = ../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
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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
 | 
					1. Whitespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Of course, the most important aspect in any coding style is whitespace.
 | 
					Of course, the most important aspect in any coding style is whitespace.
 | 
				
			||||||
@@ -44,14 +41,13 @@ Rationale:
 | 
				
			|||||||
3. Naming
 | 
					3. Naming
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Variables are lower_case_with_underscores; easy to type and read.  Structured
 | 
					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
 | 
					type names are in CamelCase; harder to type but standing out.  Scalar type
 | 
				
			||||||
names and function type names should also be in CamelCase.  Scalar type
 | 
					 | 
				
			||||||
names are lower_case_with_underscores_ending_with_a_t, like the POSIX
 | 
					names are lower_case_with_underscores_ending_with_a_t, like the POSIX
 | 
				
			||||||
uint64_t and family.  Note that this last convention contradicts POSIX
 | 
					uint64_t and family.  Note that this last convention contradicts POSIX
 | 
				
			||||||
and is therefore likely to be changed.
 | 
					and is therefore likely to be changed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When wrapping standard library functions, use the prefix qemu_ to alert
 | 
					Typedefs are used to eliminate the redundant 'struct' keyword.  It is the
 | 
				
			||||||
readers that they are seeing a wrapped version; otherwise avoid this prefix.
 | 
					QEMU coding style.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4. Block structure
 | 
					4. Block structure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,10 +65,6 @@ keyword.  Example:
 | 
				
			|||||||
        printf("a was something else entirely.\n");
 | 
					        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
 | 
					An exception is the opening brace for a function; for reasons of tradition
 | 
				
			||||||
and clarity it comes on a line by itself:
 | 
					and clarity it comes on a line by itself:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										197
									
								
								Changelog
									
									
									
									
									
								
							
							
						
						
									
										197
									
								
								Changelog
									
									
									
									
									
								
							@@ -1,8 +1,189 @@
 | 
				
			|||||||
This file documents changes for QEMU releases 0.12 and earlier.
 | 
					version 0.12.5
 | 
				
			||||||
For changelog information for later releases, see
 | 
					 - audio/alsa: Handle SND_PCM_STATE_SETUP in alsa_poll_handler
 | 
				
			||||||
http://wiki.qemu.org/ChangeLog or look at the git history for
 | 
					 - block: Handle multiwrite errors only when all requests have completed
 | 
				
			||||||
more detailed information.
 | 
					 - 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:
 | 
					version 0.12.0:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,7 +259,7 @@ version 0.10.2:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  - fix savevm/loadvm (Anthony Liguori)
 | 
					  - fix savevm/loadvm (Anthony Liguori)
 | 
				
			||||||
  - live migration: fix dirty tracking windows (Glauber Costa)
 | 
					  - 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)
 | 
					  - qcow2: fix image creation for > ~2TB images (Chris Wright)
 | 
				
			||||||
  - hotplug: fix error handling for if= parameter (Eduardo Habkost)
 | 
					  - hotplug: fix error handling for if= parameter (Eduardo Habkost)
 | 
				
			||||||
  - qcow2: fix data corruption (Nolan Leake)
 | 
					  - qcow2: fix data corruption (Nolan Leake)
 | 
				
			||||||
@@ -386,7 +567,7 @@ version 0.5.3:
 | 
				
			|||||||
  - support of CD-ROM change
 | 
					  - support of CD-ROM change
 | 
				
			||||||
  - multiple network interface support
 | 
					  - multiple network interface support
 | 
				
			||||||
  - initial x86-64 host support (Gwenole Beauchesne)
 | 
					  - 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)
 | 
					  - task switch fixes (SkyOS boot)
 | 
				
			||||||
  - VM save/restore commands
 | 
					  - VM save/restore commands
 | 
				
			||||||
  - new timer API
 | 
					  - new timer API
 | 
				
			||||||
@@ -447,7 +628,7 @@ version 0.5.0:
 | 
				
			|||||||
  - multi-target build
 | 
					  - multi-target build
 | 
				
			||||||
  - fixed: no error code in hardware interrupts
 | 
					  - fixed: no error code in hardware interrupts
 | 
				
			||||||
  - fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
 | 
					  - fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
 | 
				
			||||||
  - correct single stepping through string operations
 | 
					  - correct single stepping thru string operations
 | 
				
			||||||
  - preliminary SPARC target support (Thomas M. Ogrisegg)
 | 
					  - preliminary SPARC target support (Thomas M. Ogrisegg)
 | 
				
			||||||
  - tun-fd option (Rusty Russell)
 | 
					  - tun-fd option (Rusty Russell)
 | 
				
			||||||
  - automatic IDE geometry detection
 | 
					  - automatic IDE geometry detection
 | 
				
			||||||
@@ -531,7 +712,7 @@ version 0.1.5:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 - ppc64 support + personality() patch (Rusty Russell)
 | 
					 - ppc64 support + personality() patch (Rusty Russell)
 | 
				
			||||||
 - first Alpha CPU patches (Falk Hueffner)
 | 
					 - first Alpha CPU patches (Falk Hueffner)
 | 
				
			||||||
 - removed bfd.h dependency
 | 
					 - removed bfd.h dependancy
 | 
				
			||||||
 - fixed shrd, shld, idivl and divl on PowerPC.
 | 
					 - fixed shrd, shld, idivl and divl on PowerPC.
 | 
				
			||||||
 - fixed buggy glibc PowerPC rint() function (test-i386 passes now 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
 | 
					GNU General Public License. Hence each source file contains its own
 | 
				
			||||||
licensing information.
 | 
					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
 | 
					3) The Tiny Code Generator (TCG) is released under the BSD license
 | 
				
			||||||
   (see license headers in files).
 | 
					   (see license headers in files).
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										756
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										756
									
								
								MAINTAINERS
									
									
									
									
									
								
							@@ -1,694 +1,88 @@
 | 
				
			|||||||
QEMU Maintainers
 | 
					QEMU Maintainers
 | 
				
			||||||
================
 | 
					================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The intention of this file is not to establish who owns what portions of the
 | 
					Project leaders:
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
i.MX31
 | 
					 | 
				
			||||||
M: Peter Chubb <peter.chubb@nicta.com.au>
 | 
					 | 
				
			||||||
S: Odd fixes
 | 
					 | 
				
			||||||
F: hw/imx*
 | 
					 | 
				
			||||||
F: hw/kzm.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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
petalogix_ml605
 | 
					 | 
				
			||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: hw/petalogix_ml605_mmu.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
 | 
					 | 
				
			||||||
----------------
 | 
					----------------
 | 
				
			||||||
405
 | 
					 | 
				
			||||||
M: Alexander Graf <agraf@suse.de>
 | 
					 | 
				
			||||||
L: qemu-ppc@nongnu.org
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: hw/ppc405_boards.c
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
New World
 | 
					Fabrice Bellard
 | 
				
			||||||
M: Alexander Graf <agraf@suse.de>
 | 
					Paul Brook
 | 
				
			||||||
L: qemu-ppc@nongnu.org
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: hw/ppc_newworld.c
 | 
					 | 
				
			||||||
F: hw/unin_pci.c
 | 
					 | 
				
			||||||
F: hw/dec_pci.[hc]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Old World
 | 
					CPU cores:
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
UniCore32 Machines
 | 
					 | 
				
			||||||
-------------
 | 
					 | 
				
			||||||
PKUnity-3 SoC initramfs-with-busybox
 | 
					 | 
				
			||||||
M: Guan Xuetao <gxt@mprc.pku.edu.cn>
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: hw/puv3*
 | 
					 | 
				
			||||||
F: hw/unicore32/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Xilinx EDK
 | 
					 | 
				
			||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
 | 
					 | 
				
			||||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: hw/xilinx_axi*
 | 
					 | 
				
			||||||
F: hw/xilinx_uartlite.c
 | 
					 | 
				
			||||||
F: hw/xilinx_intc.c
 | 
					 | 
				
			||||||
F: hw/xilinx_ethlite.c
 | 
					 | 
				
			||||||
F: hw/xilinx_timer.c
 | 
					 | 
				
			||||||
F: hw/xilinx.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Subsystems
 | 
					 | 
				
			||||||
----------
 | 
					----------
 | 
				
			||||||
Audio
 | 
					 | 
				
			||||||
M: Vassili Karpov (malc) <av1474@comtv.ru>
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: audio/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Block
 | 
					x86                Fabrice Bellard
 | 
				
			||||||
M: Kevin Wolf <kwolf@redhat.com>
 | 
					ARM                Paul Brook
 | 
				
			||||||
S: Supported
 | 
					SPARC              Blue Swirl
 | 
				
			||||||
F: block*
 | 
					MIPS               Thiemo Seufer
 | 
				
			||||||
F: block/
 | 
					PowerPC            ?
 | 
				
			||||||
 | 
					M68K               Paul Brook
 | 
				
			||||||
 | 
					SH4                ?
 | 
				
			||||||
 | 
					CRIS               Edgar E. Iglesias
 | 
				
			||||||
 | 
					Alpha              ?
 | 
				
			||||||
 | 
					MicroBlaze         Edgar E. Iglesias
 | 
				
			||||||
 | 
					S390               ?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Character Devices
 | 
					Machines (sorted by CPU):
 | 
				
			||||||
M: Anthony Liguori <aliguori@us.ibm.com>
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: qemu-char.c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Device Tree
 | 
					 | 
				
			||||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
 | 
					 | 
				
			||||||
M: Alexander Graf <agraf@suse.de>
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: device-tree.[ch]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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: Stefan Hajnoczi <stefanha@gmail.com>
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: net/
 | 
					 | 
				
			||||||
T: git git://github.com/stefanha/qemu.git 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@gmail.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)
 | 
					 | 
				
			||||||
-------------------------
 | 
					-------------------------
 | 
				
			||||||
Common code
 | 
					 | 
				
			||||||
M: qemu-devel@nongnu.org
 | 
					 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: tcg/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARM target
 | 
					x86
 | 
				
			||||||
M: Andrzej Zaborowski <balrogg@gmail.com>
 | 
					  pc.c                    Fabrice Bellard (new maintainer needed)
 | 
				
			||||||
S: Maintained
 | 
					ARM
 | 
				
			||||||
F: tcg/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
 | 
					Generic Subsystems:
 | 
				
			||||||
M: Richard Henderson <rth@twiddle.net>
 | 
					-------------------  
 | 
				
			||||||
S: Maintained
 | 
					 | 
				
			||||||
F: tcg/hppa/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
i386 target
 | 
					Dynamic translator        Fabrice Bellard
 | 
				
			||||||
M: qemu-devel@nongnu.org
 | 
					Main loop                 Fabrice Bellard (new maintainer needed)
 | 
				
			||||||
S: Maintained
 | 
					TCG                       Fabrice Bellard
 | 
				
			||||||
F: tcg/i386/
 | 
					IDE device                ?
 | 
				
			||||||
 | 
					SCSI device               Paul Brook
 | 
				
			||||||
IA64 target
 | 
					PCI layer                 ?
 | 
				
			||||||
M: Aurelien Jarno <aurelien@aurel32.net>
 | 
					USB layer                 ?
 | 
				
			||||||
S: Maintained
 | 
					Block layer               ?
 | 
				
			||||||
F: tcg/ia64/
 | 
					Graphic layer             ?
 | 
				
			||||||
 | 
					Audio device layer        Vassili Karpov (malc)
 | 
				
			||||||
MIPS target
 | 
					Character device layer    ?
 | 
				
			||||||
M: Aurelien Jarno <aurelien@aurel32.net>
 | 
					Network device layer      ?
 | 
				
			||||||
S: Maintained
 | 
					GDB stub                  ?
 | 
				
			||||||
F: tcg/mips/
 | 
					Linux user                ?
 | 
				
			||||||
 | 
					Darwin user               ?
 | 
				
			||||||
PPC
 | 
					SLIRP                     ?
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										538
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										538
									
								
								Makefile
									
									
									
									
									
								
							@@ -1,15 +1,14 @@
 | 
				
			|||||||
# Makefile for QEMU.
 | 
					# Makefile for QEMU.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Always point to the root of the build tree (needs GNU make).
 | 
					# This needs to be defined before rules.mak
 | 
				
			||||||
BUILD_DIR=$(CURDIR)
 | 
					GENERATED_HEADERS = config-host.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# All following code might depend on configuration variables
 | 
					 | 
				
			||||||
ifneq ($(wildcard config-host.mak),)
 | 
					ifneq ($(wildcard config-host.mak),)
 | 
				
			||||||
# Put the all: rule here so that config-host.mak can contain dependencies.
 | 
					# Put the all: rule here so that config-host.mak can contain dependencies.
 | 
				
			||||||
all:
 | 
					all: build-all
 | 
				
			||||||
include config-host.mak
 | 
					include config-host.mak
 | 
				
			||||||
include $(SRC_PATH)/rules.mak
 | 
					include $(SRC_PATH)/rules.mak
 | 
				
			||||||
config-host.mak: $(SRC_PATH)/configure
 | 
					config-host.mak: configure
 | 
				
			||||||
	@echo $@ is out-of-date, running configure
 | 
						@echo $@ is out-of-date, running configure
 | 
				
			||||||
	@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
 | 
						@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
@@ -18,63 +17,38 @@ config-host.mak:
 | 
				
			|||||||
	@exit 1
 | 
						@exit 1
 | 
				
			||||||
endif
 | 
					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
 | 
					# Don't try to regenerate Makefile or configure
 | 
				
			||||||
# We don't generate any of them
 | 
					# We don't generate any of them
 | 
				
			||||||
Makefile: ;
 | 
					Makefile: ;
 | 
				
			||||||
configure: ;
 | 
					configure: ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: all clean cscope distclean dvi html info install install-doc \
 | 
					.PHONY: all clean cscope distclean dvi html info install install-doc \
 | 
				
			||||||
	pdf recurse-all speed test dist
 | 
						recurse-all speed tar tarbin test build-all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(call set-vpath, $(SRC_PATH))
 | 
					VPATH=$(SRC_PATH):$(SRC_PATH)/hw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LIBS+=-lz $(LIBS_TOOLS)
 | 
					LIBS+=-lz $(LIBS_TOOLS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ifdef BUILD_DOCS
 | 
					ifdef BUILD_DOCS
 | 
				
			||||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
 | 
					DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8
 | 
				
			||||||
ifdef CONFIG_VIRTFS
 | 
					 | 
				
			||||||
DOCS+=fsdev/virtfs-proxy-helper.1
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
DOCS=
 | 
					DOCS=
 | 
				
			||||||
endif
 | 
					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=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
 | 
				
			||||||
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
 | 
					config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
 | 
				
			||||||
	$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@,"  GEN   $@")
 | 
						$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@,"  GEN   $@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-include $(SUBDIR_DEVICES_MAK_DEP)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%/config-devices.mak: default-configs/%.mak
 | 
					%/config-devices.mak: default-configs/%.mak
 | 
				
			||||||
	$(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $@ $<, "  GEN   $@")
 | 
						$(call quiet-command,cat $< > $@.tmp, "  GEN   $@")
 | 
				
			||||||
	@if test -f $@; then \
 | 
						@if test -f $@ ; then \
 | 
				
			||||||
	  if cmp -s $@.old $@; then \
 | 
						  echo "WARNING: $@ out of date." ;\
 | 
				
			||||||
	    mv $@.tmp $@; \
 | 
						  echo "Run \"make defconfig\" to regenerate." ; \
 | 
				
			||||||
	    cp -p $@ $@.old; \
 | 
						  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 \
 | 
						 else \
 | 
				
			||||||
	  mv $@.tmp $@; \
 | 
						  mv $@.tmp $@ ; \
 | 
				
			||||||
	  cp -p $@ $@.old; \
 | 
					 | 
				
			||||||
	 fi
 | 
						 fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defconfig:
 | 
					defconfig:
 | 
				
			||||||
@@ -82,27 +56,34 @@ defconfig:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
-include config-all-devices.mak
 | 
					-include config-all-devices.mak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
 | 
					build-all: $(DOCS) $(TOOLS) recurse-all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config-host.h: config-host.h-timestamp
 | 
					config-host.h: config-host.h-timestamp
 | 
				
			||||||
config-host.h-timestamp: config-host.mak
 | 
					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))
 | 
					SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
subdir-%:
 | 
					ifeq ($(KVM_KMOD),yes)
 | 
				
			||||||
	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
 | 
					
 | 
				
			||||||
 | 
					.PHONEY: kvm-kmod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: kvm-kmod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					kvm-kmod:
 | 
				
			||||||
 | 
						$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C kvm/kernel V="$(V)" )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifneq ($(wildcard config-host.mak),)
 | 
					 | 
				
			||||||
include $(SRC_PATH)/Makefile.objs
 | 
					 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o
 | 
					subdir-%: $(GENERATED_HEADERS)
 | 
				
			||||||
 | 
						$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) subdir-libdis
 | 
					$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) subdir-libdis-user subdir-libuser
 | 
					$(filter %-user,$(SUBDIR_RULES)): libuser.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libuser.a: $(GENERATED_HEADERS)
 | 
				
			||||||
 | 
						$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libuser V="$(V)" TARGET_DIR="libuser/" all,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
 | 
					ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
 | 
				
			||||||
romsubdir-%:
 | 
					romsubdir-%:
 | 
				
			||||||
@@ -112,218 +93,255 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
 | 
					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/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+=$(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 hw/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)
 | 
					bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
version.o: $(SRC_PATH)/version.rc config-host.h
 | 
					libqemu_common.a: $(obj-y)
 | 
				
			||||||
	$(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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: $(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-img-cmds.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
 | 
					qemu-img$(EXESUF): qemu-img.o qemu-tool.o $(block-obj-y) $(qobject-obj-y)
 | 
				
			||||||
	qemu-timer-common.o main-loop.o notify.o \
 | 
					 | 
				
			||||||
	iohandler.o cutils.o iov.o async.o
 | 
					 | 
				
			||||||
tools-obj-$(CONFIG_POSIX) += compatfd.o
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
 | 
					qemu-nbd$(EXESUF):  qemu-nbd.o qemu-tool.o $(block-obj-y) $(qobject-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-bridge-helper$(EXESUF): qemu-bridge-helper.o
 | 
					qemu-io$(EXESUF):  qemu-io.o qemu-tool.o cmd.o $(block-obj-y) $(qobject-obj-y)
 | 
				
			||||||
 | 
					 | 
				
			||||||
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) $(tools-obj-y) qemu-timer-common.o libcacard/vscclient.o
 | 
					 | 
				
			||||||
	$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS),"  LINK  $@")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 | 
					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   $@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
 | 
					check-qint: check-qint.o qint.o qemu-malloc.o
 | 
				
			||||||
qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
 | 
					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
 | 
				
			||||||
gen-out-type = $(subst .,-,$(suffix $@))
 | 
					check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
 | 
				
			||||||
 | 
					check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o
 | 
				
			||||||
ifneq ($(wildcard config-host.mak),)
 | 
					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
 | 
				
			||||||
include $(SRC_PATH)/tests/Makefile
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
 | 
					 | 
				
			||||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
 | 
					 | 
				
			||||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 | 
					 | 
				
			||||||
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
 | 
					 | 
				
			||||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
 | 
					 | 
				
			||||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 | 
					 | 
				
			||||||
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
 | 
					 | 
				
			||||||
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
 | 
					 | 
				
			||||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qapi-types.c qapi-types.h :\
 | 
					 | 
				
			||||||
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-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 $(qapi-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 $(qapi-py)
 | 
					 | 
				
			||||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, "  GEN   $@")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
 | 
					 | 
				
			||||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
# avoid old build problems by removing potentially incorrect old files
 | 
					# 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 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 $(TOOLS) TAGS cscope.* *.pod *~ */*~
 | 
				
			||||||
	find . -name '*.[od]' -exec rm -f {} +
 | 
						rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d
 | 
				
			||||||
	rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
 | 
					 | 
				
			||||||
	rm -Rf .libs
 | 
					 | 
				
			||||||
	rm -f qemu-img-cmds.h
 | 
						rm -f qemu-img-cmds.h
 | 
				
			||||||
	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
 | 
						$(MAKE) -C tests clean
 | 
				
			||||||
	@# May not be present in GENERATED_HEADERS
 | 
						for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser; do \
 | 
				
			||||||
	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-generated
 | 
					 | 
				
			||||||
	rm -rf qga/qapi-generated
 | 
					 | 
				
			||||||
	$(MAKE) -C tests/tcg clean
 | 
					 | 
				
			||||||
	for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
 | 
					 | 
				
			||||||
	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
 | 
						if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
 | 
				
			||||||
	rm -f $$d/qemu-options.def; \
 | 
					 | 
				
			||||||
        done
 | 
					        done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VERSION ?= $(shell cat VERSION)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dist: qemu-$(VERSION).tar.bz2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qemu-%.tar.bz2:
 | 
					 | 
				
			||||||
	$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
distclean: clean
 | 
					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-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 config-all-devices.mak
 | 
				
			||||||
	rm -f roms/seabios/config.mak roms/vgabios/config.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,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
 | 
				
			||||||
	rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
 | 
						for d in $(TARGET_DIRS) libhw32 libhw64 libuser; do \
 | 
				
			||||||
	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 -rf $$d || exit 1 ; \
 | 
						rm -rf $$d || exit 1 ; \
 | 
				
			||||||
        done
 | 
					        done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
KEYMAPS=da     en-gb  et  fr     fr-ch  is  lt  modifiers  no  pt-br  sv \
 | 
					KEYMAPS=da     en-gb  et  fr     fr-ch  is  lt  modifiers  no  pt-br  sv \
 | 
				
			||||||
ar      de     en-us  fi  fr-be  hr     it  lv  nl         pl  ru     th \
 | 
					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 \
 | 
					common  de-ch  es     fo  fr-ca  hu     ja  mk  nl-be      pt  sl     tr
 | 
				
			||||||
bepo
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef INSTALL_BLOBS
 | 
					ifdef INSTALL_BLOBS
 | 
				
			||||||
BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
 | 
					BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
 | 
				
			||||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
 | 
					video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
 | 
				
			||||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
 | 
					pxe-e1000.bin pxe-i82559er.bin \
 | 
				
			||||||
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
 | 
					pxe-ne2k_pci.bin pxe-pcnet.bin \
 | 
				
			||||||
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
 | 
					pxe-rtl8139.bin pxe-virtio.bin \
 | 
				
			||||||
qemu-icon.bmp \
 | 
					bamboo.dtb petalogix-s3adsp1800.dtb \
 | 
				
			||||||
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
 | 
					multiboot.bin linuxboot.bin
 | 
				
			||||||
multiboot.bin linuxboot.bin kvmvapic.bin \
 | 
					BLOBS += extboot.bin
 | 
				
			||||||
s390-zipl.rom \
 | 
					BLOBS += vapic.bin
 | 
				
			||||||
spapr-rtas.bin slof.bin \
 | 
					 | 
				
			||||||
palcode-clipper
 | 
					 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
BLOBS=
 | 
					BLOBS=
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install-doc: $(DOCS)
 | 
					install-doc: $(DOCS)
 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
 | 
						$(INSTALL_DIR) "$(DESTDIR)$(docdir)"
 | 
				
			||||||
	$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
 | 
						$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(docdir)"
 | 
				
			||||||
	$(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
 | 
					 | 
				
			||||||
ifdef CONFIG_POSIX
 | 
					ifdef CONFIG_POSIX
 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 | 
						$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 | 
				
			||||||
	$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
 | 
						$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
 | 
						$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
 | 
				
			||||||
	$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
 | 
						$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
ifdef CONFIG_VIRTFS
 | 
					 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 | 
					 | 
				
			||||||
	$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install-datadir:
 | 
					install: all $(if $(BUILD_DOCS),install-doc)
 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install-confdir:
 | 
					 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install-sysconfig: install-datadir install-confdir
 | 
					 | 
				
			||||||
	$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
 | 
					 | 
				
			||||||
	$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/cpus-x86_64.conf "$(DESTDIR)$(qemu_datadir)"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig install-datadir
 | 
					 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
 | 
						$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
 | 
				
			||||||
ifneq ($(TOOLS),)
 | 
					ifneq ($(TOOLS),)
 | 
				
			||||||
	$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
 | 
						$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
ifneq ($(HELPERS-y),)
 | 
					 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
 | 
					 | 
				
			||||||
	$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
ifneq ($(BLOBS),)
 | 
					ifneq ($(BLOBS),)
 | 
				
			||||||
 | 
						$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
 | 
				
			||||||
	set -e; for x in $(BLOBS); do \
 | 
						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
 | 
						done
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
 | 
						$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
 | 
				
			||||||
	set -e; for x in $(KEYMAPS); do \
 | 
						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
 | 
						done
 | 
				
			||||||
	for d in $(TARGET_DIRS); do \
 | 
						for d in $(TARGET_DIRS); do \
 | 
				
			||||||
	$(MAKE) -C $$d $@ || exit 1 ; \
 | 
						$(MAKE) -C $$d $@ || exit 1 ; \
 | 
				
			||||||
        done
 | 
					        done
 | 
				
			||||||
 | 
					ifeq ($(KVM_KMOD),yes)
 | 
				
			||||||
 | 
						$(MAKE) -C kvm/kernel $@
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# various test targets
 | 
					# various test targets
 | 
				
			||||||
test speed: all
 | 
					test speed: all
 | 
				
			||||||
	$(MAKE) -C tests/tcg $@
 | 
						$(MAKE) -C tests $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: TAGS
 | 
					.PHONY: TAGS
 | 
				
			||||||
TAGS:
 | 
					TAGS:
 | 
				
			||||||
@@ -331,75 +349,121 @@ TAGS:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
cscope:
 | 
					cscope:
 | 
				
			||||||
	rm -f ./cscope.*
 | 
						rm -f ./cscope.*
 | 
				
			||||||
	find "$(SRC_PATH)" -name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
 | 
						find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files
 | 
				
			||||||
	cscope -b
 | 
						cscope -b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# documentation
 | 
					# 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
 | 
					%.html: %.texi
 | 
				
			||||||
	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \
 | 
						$(call quiet-command,texi2html -I=. -monolithic -number $<,"  GEN   $@")
 | 
				
			||||||
	"  GEN   $@")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
%.info: %.texi
 | 
					%.info: %.texi
 | 
				
			||||||
	$(call quiet-command,$(MAKEINFO) $< -o $@,"  GEN   $@")
 | 
						$(call quiet-command,makeinfo -I . $< -o $@,"  GEN   $@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%.pdf: %.texi
 | 
					%.dvi: %.texi
 | 
				
			||||||
	$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<,"  GEN   $@")
 | 
						$(call quiet-command,texi2dvi -I . $<,"  GEN   $@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-options.texi: $(SRC_PATH)/qemu-options.hx
 | 
					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
 | 
					qemu-monitor.texi: $(SRC_PATH)/qemu-monitor.hx
 | 
				
			||||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
 | 
						$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@,"  GEN   $@")
 | 
				
			||||||
 | 
					 | 
				
			||||||
QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
 | 
					 | 
				
			||||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@,"  GEN   $@")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
 | 
					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
 | 
					qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
 | 
				
			||||||
	$(call quiet-command, \
 | 
						$(call quiet-command, \
 | 
				
			||||||
	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
 | 
						  perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod && \
 | 
				
			||||||
	  $(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
 | 
						  pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
 | 
				
			||||||
	  "  GEN   $@")
 | 
						  "  GEN   $@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-img.1: qemu-img.texi qemu-img-cmds.texi
 | 
					qemu-img.1: qemu-img.texi qemu-img-cmds.texi
 | 
				
			||||||
	$(call quiet-command, \
 | 
						$(call quiet-command, \
 | 
				
			||||||
	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
 | 
						  perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod && \
 | 
				
			||||||
	  $(POD2MAN) --section=1 --center=" " --release=" " 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 > $@, \
 | 
					 | 
				
			||||||
	  "  GEN   $@")
 | 
						  "  GEN   $@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-nbd.8: qemu-nbd.texi
 | 
					qemu-nbd.8: qemu-nbd.texi
 | 
				
			||||||
	$(call quiet-command, \
 | 
						$(call quiet-command, \
 | 
				
			||||||
	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
 | 
						  perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod && \
 | 
				
			||||||
	  $(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
 | 
						  pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
 | 
				
			||||||
	  "  GEN   $@")
 | 
						  "  GEN   $@")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dvi: qemu-doc.dvi qemu-tech.dvi
 | 
					 | 
				
			||||||
html: qemu-doc.html qemu-tech.html
 | 
					 | 
				
			||||||
info: qemu-doc.info qemu-tech.info
 | 
					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: \
 | 
					dvi: qemu-doc.dvi qemu-tech.dvi
 | 
				
			||||||
	qemu-img.texi qemu-nbd.texi qemu-options.texi \
 | 
					 | 
				
			||||||
	qemu-monitor.texi qemu-img-cmds.texi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Add a dependency on the generated files, so that they are always
 | 
					html: qemu-doc.html qemu-tech.html
 | 
				
			||||||
# rebuilt before other object files
 | 
					
 | 
				
			||||||
Makefile: $(GENERATED_HEADERS)
 | 
					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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# tar release (use 'make -k tar' on a checkouted tree)
 | 
				
			||||||
 | 
					tar:
 | 
				
			||||||
 | 
						rm -rf /tmp/$(FILE)
 | 
				
			||||||
 | 
						cp -r . /tmp/$(FILE)
 | 
				
			||||||
 | 
						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 automatically generated dependency files
 | 
				
			||||||
# Dependencies in Makefile.objs files come from our recursive subdir rules
 | 
					-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d)
 | 
				
			||||||
-include $(wildcard *.d tests/*.d)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								Makefile.dis
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								Makefile.dis
									
									
									
									
									
								
							@@ -1,20 +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 *~
 | 
					 | 
				
			||||||
							
								
								
									
										46
									
								
								Makefile.hw
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								Makefile.hw
									
									
									
									
									
								
							@@ -7,17 +7,49 @@ include $(SRC_PATH)/rules.mak
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.PHONY: all
 | 
					.PHONY: all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(call set-vpath, $(SRC_PATH))
 | 
					VPATH=$(SRC_PATH):$(SRC_PATH)/hw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QEMU_CFLAGS+=-I..
 | 
					QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
 | 
				
			||||||
QEMU_CFLAGS += -I$(SRC_PATH)/include
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
					# Dummy command so that make thinks it has done something
 | 
				
			||||||
	@true
 | 
						@true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(HWLIB): $(obj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	rm -f $(addsuffix *.o, $(sort $(dir $(hw-obj-y))))
 | 
						rm -f *.o *.d *.a *~
 | 
				
			||||||
	rm -f $(addsuffix *.d, $(sort $(dir $(hw-obj-y))))
 | 
					
 | 
				
			||||||
 | 
					# Include automatically generated dependency files
 | 
				
			||||||
 | 
					-include $(wildcard *.d */*.d)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										250
									
								
								Makefile.objs
									
									
									
									
									
								
							
							
						
						
									
										250
									
								
								Makefile.objs
									
									
									
									
									
								
							@@ -1,250 +0,0 @@
 | 
				
			|||||||
#######################################################################
 | 
					 | 
				
			||||||
# Target-independent parts used in system and user emulation
 | 
					 | 
				
			||||||
universal-obj-y =
 | 
					 | 
				
			||||||
universal-obj-y += qemu-log.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#######################################################################
 | 
					 | 
				
			||||||
# 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
 | 
					 | 
				
			||||||
qom-obj-y = qom/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 iov.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-obj-y += block/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
######################################################################
 | 
					 | 
				
			||||||
# 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.o net/
 | 
					 | 
				
			||||||
common-obj-y += qom/
 | 
					 | 
				
			||||||
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-$(CONFIG_LINUX) += fsdev/
 | 
					 | 
				
			||||||
extra-obj-$(CONFIG_LINUX) += fsdev/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
common-obj-y += tcg-runtime.o host-utils.o main-loop.o
 | 
					 | 
				
			||||||
common-obj-y += input.o
 | 
					 | 
				
			||||||
common-obj-y += buffered_file.o migration.o migration-tcp.o
 | 
					 | 
				
			||||||
common-obj-y += qemu-char.o #aio.o
 | 
					 | 
				
			||||||
common-obj-y += block-migration.o iohandler.o
 | 
					 | 
				
			||||||
common-obj-y += pflib.o
 | 
					 | 
				
			||||||
common-obj-y += bitmap.o bitops.o
 | 
					 | 
				
			||||||
common-obj-y += page_cache.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_WIN32) += version.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
common-obj-y += audio/
 | 
					 | 
				
			||||||
common-obj-y += hw/
 | 
					 | 
				
			||||||
common-obj-y += ui/
 | 
					 | 
				
			||||||
common-obj-y += bt-host.o bt-vhci.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_SLIRP) += slirp/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
######################################################################
 | 
					 | 
				
			||||||
# libseccomp
 | 
					 | 
				
			||||||
ifeq ($(CONFIG_SECCOMP),y)
 | 
					 | 
				
			||||||
common-obj-y += qemu-seccomp.o
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
######################################################################
 | 
					 | 
				
			||||||
# 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 iov.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/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
######################################################################
 | 
					 | 
				
			||||||
# libhw
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
hw-obj-y = vl.o dma-helpers.o qtest.o hw/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
######################################################################
 | 
					 | 
				
			||||||
# 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-obj-$(CONFIG_TRACE_DEFAULT) += trace/default.o
 | 
					 | 
				
			||||||
trace-obj-$(CONFIG_TRACE_SIMPLE) += trace/simple.o
 | 
					 | 
				
			||||||
trace-obj-$(CONFIG_TRACE_SIMPLE) += qemu-timer-common.o
 | 
					 | 
				
			||||||
trace-obj-$(CONFIG_TRACE_STDERR) += trace/stderr.o
 | 
					 | 
				
			||||||
trace-obj-y += trace/control.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$(trace-obj-y): $(GENERATED_HEADERS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
######################################################################
 | 
					 | 
				
			||||||
# smartcard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
libcacard-y += libcacard/cac.o libcacard/event.o
 | 
					 | 
				
			||||||
libcacard-y += libcacard/vcard.o libcacard/vreader.o
 | 
					 | 
				
			||||||
libcacard-y += libcacard/vcard_emul_nss.o
 | 
					 | 
				
			||||||
libcacard-y += libcacard/vcard_emul_type.o
 | 
					 | 
				
			||||||
libcacard-y += libcacard/card_7816.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
######################################################################
 | 
					 | 
				
			||||||
# qapi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qapi-obj-y = qapi/
 | 
					 | 
				
			||||||
qapi-obj-y += qapi-types.o qapi-visit.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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-obj-y = qga/ 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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
nested-vars += \
 | 
					 | 
				
			||||||
	hw-obj-y \
 | 
					 | 
				
			||||||
	qga-obj-y \
 | 
					 | 
				
			||||||
	block-obj-y \
 | 
					 | 
				
			||||||
	qom-obj-y \
 | 
					 | 
				
			||||||
	qapi-obj-y \
 | 
					 | 
				
			||||||
	user-obj-y \
 | 
					 | 
				
			||||||
	common-obj-y \
 | 
					 | 
				
			||||||
	extra-obj-y
 | 
					 | 
				
			||||||
dummy := $(call unnest-vars)
 | 
					 | 
				
			||||||
							
								
								
									
										414
									
								
								Makefile.target
									
									
									
									
									
								
							
							
						
						
									
										414
									
								
								Makefile.target
									
									
									
									
									
								
							@@ -1,216 +1,368 @@
 | 
				
			|||||||
# -*- Mode: makefile -*-
 | 
					# -*- Mode: makefile -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This needs to be defined before rules.mak
 | 
				
			||||||
 | 
					GENERATED_HEADERS = config-target.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include ../config-host.mak
 | 
					include ../config-host.mak
 | 
				
			||||||
include config-devices.mak
 | 
					include config-devices.mak
 | 
				
			||||||
include config-target.mak
 | 
					include config-target.mak
 | 
				
			||||||
include $(SRC_PATH)/rules.mak
 | 
					include $(SRC_PATH)/rules.mak
 | 
				
			||||||
ifneq ($(HWDIR),)
 | 
					 | 
				
			||||||
include $(HWDIR)/config.mak
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(call set-vpath, $(SRC_PATH))
 | 
					TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
 | 
				
			||||||
ifdef CONFIG_LINUX
 | 
					VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
 | 
				
			||||||
QEMU_CFLAGS += -I../linux-headers
 | 
					QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -DNEED_CPU_H
 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -DNEED_CPU_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
QEMU_CFLAGS+=-I$(SRC_PATH)/include
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_USER_ONLY
 | 
					ifdef CONFIG_USER_ONLY
 | 
				
			||||||
# user emulator name
 | 
					# user emulator name
 | 
				
			||||||
QEMU_PROG=qemu-$(TARGET_ARCH2)
 | 
					QEMU_PROG=qemu-$(TARGET_ARCH2)
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
# system emulator name
 | 
					# system emulator name
 | 
				
			||||||
ifneq (,$(findstring -mwindows,$(LIBS)))
 | 
					ifeq ($(TARGET_ARCH), i386)
 | 
				
			||||||
# Terminate program name with a 'w' because the linker builds a windows executable.
 | 
					QEMU_PROG=qemu$(EXESUF)
 | 
				
			||||||
QEMU_PROGW=qemu-system-$(TARGET_ARCH2)w$(EXESUF)
 | 
					else
 | 
				
			||||||
endif # windows executable
 | 
					 | 
				
			||||||
QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
 | 
					QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PROGS=$(QEMU_PROG)
 | 
					PROGS=$(QEMU_PROG)
 | 
				
			||||||
ifdef QEMU_PROGW
 | 
					 | 
				
			||||||
PROGS+=$(QEMU_PROGW)
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
STPFILES=
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifndef CONFIG_HAIKU
 | 
					 | 
				
			||||||
LIBS+=-lm
 | 
					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: config-target.h-timestamp
 | 
				
			||||||
config-target.h-timestamp: config-target.mak
 | 
					config-target.h-timestamp: config-target.mak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_TRACE_SYSTEMTAP
 | 
					all: $(PROGS)
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Dummy command so that make thinks it has done something
 | 
					# Dummy command so that make thinks it has done something
 | 
				
			||||||
	@true
 | 
						@true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#########################################################
 | 
					#########################################################
 | 
				
			||||||
# cpu emulator library
 | 
					# cpu emulator library
 | 
				
			||||||
obj-y = exec.o translate-all.o cpu-exec.o
 | 
					libobj-y = exec.o cpu-exec.o
 | 
				
			||||||
obj-y += tcg/tcg.o tcg/optimize.o
 | 
					libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o
 | 
				
			||||||
obj-$(CONFIG_TCG_INTERPRETER) += tci.o
 | 
					libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o
 | 
				
			||||||
obj-y += fpu/softfloat.o
 | 
					libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o
 | 
				
			||||||
obj-y += disas.o
 | 
					libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
 | 
				
			||||||
obj-$(CONFIG_TCI_DIS) += tci-dis.o
 | 
					libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
 | 
				
			||||||
obj-y += target-$(TARGET_BASE_ARCH)/
 | 
					libobj-y += op_helper.o helper.o
 | 
				
			||||||
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 | 
					libobj-$(CONFIG_NEED_MMU) += mmu.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci
 | 
					libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
 | 
				
			||||||
 | 
					libobj-$(CONFIG_KVM) += qemu-kvm-helper.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# HELPER_CFLAGS is used for all the legacy code compiled with static register
 | 
					libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 | 
				
			||||||
 | 
					libobj-$(TARGET_ALPHA) += alpha_palcode.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NOTE: the disassembler code is only needed for debugging
 | 
				
			||||||
 | 
					libobj-y += disas.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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# libqemu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libqemu.a: $(libobj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
					# variables
 | 
				
			||||||
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
 | 
					# 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)
 | 
					signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qemu-kvm-helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#########################################################
 | 
					#########################################################
 | 
				
			||||||
# Linux user emulator target
 | 
					# Linux user emulator target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_LINUX_USER
 | 
					ifdef CONFIG_LINUX_USER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-y += linux-user/
 | 
					obj-$(TARGET_HAS_BFLT) += flatload.o
 | 
				
			||||||
obj-y += gdbstub.o thunk.o user-exec.o $(oslib-obj-y)
 | 
					obj-$(TARGET_HAS_ELFLOAD32) += elfload32.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(TARGET_I386) += vm86.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-i386-y += ioport-user.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					nwfpe-obj-y = fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o fpopcode.o
 | 
				
			||||||
 | 
					nwfpe-obj-y += single_cpdo.o double_cpdo.o extended_cpdo.o
 | 
				
			||||||
 | 
					obj-arm-y +=  $(addprefix nwfpe/, $(nwfpe-obj-y))
 | 
				
			||||||
 | 
					obj-arm-y += arm-semi.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-m68k-y += m68k-sim.o m68k-semi.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ARLIBS=../libuser/libuser.a libqemu.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif #CONFIG_LINUX_USER
 | 
					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
 | 
					# BSD user emulator target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_BSD_USER
 | 
					ifdef CONFIG_BSD_USER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VPATH+=:$(SRC_PATH)/bsd-user
 | 
				
			||||||
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
 | 
					QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-y += bsd-user/
 | 
					obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
 | 
				
			||||||
obj-y += gdbstub.o user-exec.o $(oslib-obj-y)
 | 
					        gdbstub.o uaccess.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-i386-y += ioport-user.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ARLIBS=../libuser/libuser.a libqemu.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif #CONFIG_BSD_USER
 | 
					endif #CONFIG_BSD_USER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#########################################################
 | 
					#########################################################
 | 
				
			||||||
# System emulator target
 | 
					# System emulator target
 | 
				
			||||||
ifdef CONFIG_SOFTMMU
 | 
					ifdef CONFIG_SOFTMMU
 | 
				
			||||||
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)
 | 
					 | 
				
			||||||
CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y)
 | 
					 | 
				
			||||||
CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-y += arch_init.o cpus.o monitor.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
 | 
				
			||||||
obj-y += hw/
 | 
					# virtio has to be here due to weird dependency between PCI and virtio-net.
 | 
				
			||||||
obj-$(CONFIG_KVM) += kvm-all.o
 | 
					# need to fix this properly
 | 
				
			||||||
obj-$(CONFIG_NO_KVM) += kvm-stub.o
 | 
					obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
 | 
				
			||||||
obj-y += memory.o savevm.o cputlb.o
 | 
					obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 | 
				
			||||||
obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o
 | 
					# MSI-X depends on kvm for interrupt injection,
 | 
				
			||||||
obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o
 | 
					# so moved it from Makefile.hw to Makefile.target for now
 | 
				
			||||||
obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o
 | 
					obj-y += msix.o
 | 
				
			||||||
obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 | 
				
			||||||
LIBS+=-lz
 | 
					LIBS+=-lz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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_TLS_CFLAGS)
 | 
				
			||||||
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 | 
					QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 | 
				
			||||||
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
 | 
					 | 
				
			||||||
QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# xen support
 | 
					# xen backend driver support
 | 
				
			||||||
obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o
 | 
					obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 | 
				
			||||||
obj-$(CONFIG_NO_XEN) += xen-stub.o
 | 
					
 | 
				
			||||||
 | 
					# USB layer
 | 
				
			||||||
 | 
					obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PCI network cards
 | 
				
			||||||
 | 
					obj-y += eepro100.o
 | 
				
			||||||
 | 
					obj-y += pcnet.o
 | 
				
			||||||
 | 
					obj-y += rtl8139.o
 | 
				
			||||||
 | 
					obj-y += e1000.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Hardware support
 | 
					# Hardware support
 | 
				
			||||||
 | 
					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 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 += 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 += heathrow_pic.o grackle_pci.o ppc_oldworld.o
 | 
				
			||||||
 | 
					# NewWorld PowerMac
 | 
				
			||||||
 | 
					obj-ppc-y += unin_pci.o ppc_newworld.o
 | 
				
			||||||
 | 
					# PowerPC 4xx boards
 | 
				
			||||||
 | 
					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_pci.o ppce500_mpc8544ds.o
 | 
				
			||||||
 | 
					obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
 | 
				
			||||||
 | 
					obj-ppc-$(CONFIG_FDT) += device_tree.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.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 += 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 += pflash_cfi02.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-microblaze-$(CONFIG_FDT) += device_tree.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Boards
 | 
				
			||||||
 | 
					obj-cris-y = cris_pic_cpu.o etraxfs.o axis_dev88.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# IO blocks
 | 
				
			||||||
 | 
					obj-cris-y += etraxfs_dma.o
 | 
				
			||||||
 | 
					obj-cris-y += etraxfs_pic.o
 | 
				
			||||||
 | 
					obj-cris-y += etraxfs_eth.o
 | 
				
			||||||
 | 
					obj-cris-y += etraxfs_timer.o
 | 
				
			||||||
 | 
					obj-cris-y += etraxfs_ser.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-cris-y += pflash_cfi02.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(TARGET_ARCH), sparc64)
 | 
					ifeq ($(TARGET_ARCH), sparc64)
 | 
				
			||||||
obj-y += hw/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
 | 
					else
 | 
				
			||||||
obj-y += hw/$(TARGET_BASE_ARCH)/
 | 
					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
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 | 
					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 += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 | 
				
			||||||
 | 
					obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
 | 
				
			||||||
 | 
					obj-arm-y += pl061.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 += 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 vga.o cbus.o tusb6010.o usb-musb.o
 | 
				
			||||||
 | 
					obj-arm-y += mst_fpga.o mainstone.o
 | 
				
			||||||
 | 
					obj-arm-y += musicpal.o pflash_cfi02.o bitbang_i2c.o marvell_88w8618_audio.o
 | 
				
			||||||
 | 
					obj-arm-y += framebuffer.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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GENERATED_HEADERS += hmp-commands.h qmp-commands-old.h
 | 
					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 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(TARGET_ARCH), ia64)
 | 
				
			||||||
 | 
					firmware.o: firmware.c
 | 
				
			||||||
 | 
						$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vl.o: qemu-options.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					monitor.o: qemu-monitor.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ARLIBS=../libqemu_common.a libqemu.a $(HWLIB)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif # CONFIG_SOFTMMU
 | 
					endif # CONFIG_SOFTMMU
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nested-vars += obj-y
 | 
					obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# This resolves all nested paths, so it must come last
 | 
					$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) $(ARLIBS)
 | 
				
			||||||
include $(SRC_PATH)/Makefile.objs
 | 
						$(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all-obj-y = $(obj-y)
 | 
					 | 
				
			||||||
all-obj-y += $(addprefix ../, $(universal-obj-y))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_SOFTMMU
 | 
					gdbstub-xml.c: $(TARGET_XML_FILES) feature_to_c.sh
 | 
				
			||||||
all-obj-y += $(addprefix ../, $(common-obj-y))
 | 
						$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES),"  GEN   $(TARGET_DIR)$@")
 | 
				
			||||||
all-obj-y += $(addprefix ../libdis/, $(libdis-y))
 | 
					 | 
				
			||||||
all-obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
 | 
					 | 
				
			||||||
all-obj-y += $(addprefix ../, $(trace-obj-y))
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
all-obj-y += $(addprefix ../libuser/, $(user-obj-y))
 | 
					 | 
				
			||||||
all-obj-y += $(addprefix ../libdis-user/, $(libdis-y))
 | 
					 | 
				
			||||||
endif #CONFIG_LINUX_USER
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef QEMU_PROGW
 | 
					qemu-options.h: $(SRC_PATH)/qemu-options.hx
 | 
				
			||||||
# The linker builds a windows executable. Make also a console executable.
 | 
						$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 | 
				
			||||||
$(QEMU_PROGW): $(all-obj-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): $(all-obj-y)
 | 
					 | 
				
			||||||
	$(call LINK,$^)
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
 | 
					qemu-monitor.h: $(SRC_PATH)/qemu-monitor.hx
 | 
				
			||||||
	$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"  GEN   $(TARGET_DIR)$@")
 | 
						$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 | 
				
			||||||
 | 
					 | 
				
			||||||
hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
 | 
					 | 
				
			||||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx
 | 
					 | 
				
			||||||
	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	rm -f *.a *~ $(PROGS)
 | 
						rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
 | 
				
			||||||
	rm -f $(shell find . -name '*.[od]')
 | 
						rm -f *.d */*.d tcg/*.o ide/*.o
 | 
				
			||||||
	rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
 | 
						rm -f qemu-options.h qemu-monitor.h gdbstub-xml.c
 | 
				
			||||||
ifdef CONFIG_TRACE_SYSTEMTAP
 | 
					 | 
				
			||||||
	rm -f *.stp
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: all
 | 
					install: all
 | 
				
			||||||
ifneq ($(PROGS),)
 | 
					ifneq ($(PROGS),)
 | 
				
			||||||
	$(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)"
 | 
						$(INSTALL) -m 755 $(STRIP_OPT) $(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"
 | 
					 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GENERATED_HEADERS += config-target.h
 | 
					# Include automatically generated dependency files
 | 
				
			||||||
Makefile: $(GENERATED_HEADERS)
 | 
					-include $(wildcard *.d */*.d)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,19 +6,27 @@ include $(SRC_PATH)/rules.mak
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.PHONY: all
 | 
					.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..
 | 
				
			||||||
QEMU_CFLAGS += -I$(SRC_PATH)/include
 | 
					 | 
				
			||||||
QEMU_CFLAGS += -DCONFIG_USER_ONLY
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
					# Dummy command so that make thinks it has done something
 | 
				
			||||||
	@true
 | 
						@true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libuser.a: $(obj-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	for d in . trace; do \
 | 
						rm -f *.o *.d *.a *~
 | 
				
			||||||
	rm -f $$d/*.o $$d/*.d $$d/*.a $$d/*~; \
 | 
					
 | 
				
			||||||
	done
 | 
					# Include automatically generated dependency files
 | 
				
			||||||
 | 
					-include $(wildcard *.d */*.d)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										77
									
								
								QMP/README
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								QMP/README
									
									
									
									
									
								
							@@ -7,82 +7,57 @@ Introduction
 | 
				
			|||||||
The QEMU Monitor Protocol (QMP) allows applications to communicate with
 | 
					The QEMU Monitor Protocol (QMP) allows applications to communicate with
 | 
				
			||||||
QEMU's Monitor.
 | 
					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
 | 
					- Lightweight, text-based, easy to parse data format
 | 
				
			||||||
- Asynchronous messages support (ie. events)
 | 
					- Asynchronous events support 
 | 
				
			||||||
- Capabilities Negotiation
 | 
					- 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-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
 | 
				
			||||||
o qmp-events.txt    List of available asynchronous events
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
There is also a simple Python script called 'qmp-shell' available.
 | 
					There are also two simple Python scripts 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.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					o qmp-shell       A shell
 | 
				
			||||||
 | 
					o vm-info         Show some information about the Virtual Machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[1] http://www.json.org
 | 
					[1] http://www.json.org
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Usage
 | 
					Usage
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To enable QMP, you need a QEMU monitor instance in "control mode". There are
 | 
					To enable QMP, QEMU has to be started in "control mode". There are
 | 
				
			||||||
two ways of doing this.
 | 
					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
 | 
					For example:
 | 
				
			||||||
example makes QMP available on localhost port 4444:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $ qemu [...] -qmp tcp:localhost:4444,server
 | 
					$ qemu [...] -qmp tcp:localhost:4444,server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
However, in order to have more complex combinations, like multiple monitors,
 | 
					Will start QEMU in control mode, waiting for a client TCP connection
 | 
				
			||||||
the '-mon' command-line option should be used along with the '-chardev' one.
 | 
					on localhost port 4444.
 | 
				
			||||||
For instance, the following example creates one user monitor on stdio and one
 | 
					 | 
				
			||||||
QMP monitor on localhost port 4444.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   $ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
 | 
					It is also possible to use the '-mon' command-line option to have
 | 
				
			||||||
                -chardev socket,id=mon1,host=localhost,port=4444,server \
 | 
					more complex combinations. Please, refer to the QEMU's manpage for
 | 
				
			||||||
                -mon chardev=mon1,mode=control
 | 
					more information.
 | 
				
			||||||
 | 
					 | 
				
			||||||
Please, refer to QEMU's manpage for more information.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Simple Testing
 | 
					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
 | 
					$ telnet localhost 4444
 | 
				
			||||||
Trying 127.0.0.1...
 | 
					Trying 127.0.0.1...
 | 
				
			||||||
Connected to localhost.
 | 
					Connected to localhost.
 | 
				
			||||||
Escape character is '^]'.
 | 
					Escape character is '^]'.
 | 
				
			||||||
{"QMP": {"version": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}, "capabilities": []}}
 | 
					{"QMP": {"capabilities": []}}
 | 
				
			||||||
{ "execute": "qmp_capabilities" }
 | 
					 | 
				
			||||||
{"return": {}}
 | 
					 | 
				
			||||||
{ "execute": "query-version" }
 | 
					{ "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
 | 
					http://www.linux-kvm.org/page/MonitorProtocol
 | 
				
			||||||
existing ones) it's mandatory to update the relevant documentation, which is
 | 
					Luiz Fernando N. Capitulino <lcapitulino@redhat.com>
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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,388 +1,26 @@
 | 
				
			|||||||
                   QEMU Monitor Protocol Events
 | 
					                   QEMU Monitor Protocol: Events
 | 
				
			||||||
                   ============================
 | 
					                   =============================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BALLOON_CHANGE
 | 
					1 SHUTDOWN
 | 
				
			||||||
--------------
 | 
					-----------
 | 
				
			||||||
 | 
					 | 
				
			||||||
Emitted when the guest changes the actual BALLOON level. This
 | 
					 | 
				
			||||||
value is equivalent to the 'actual' field return by the
 | 
					 | 
				
			||||||
'query-balloon' command
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Data:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- "actual": actual level of the guest memory balloon in bytes (json-number)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Example:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{ "event": "BALLOON_CHANGE",
 | 
					 | 
				
			||||||
    "data": { "actual": 944766976 },
 | 
					 | 
				
			||||||
    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Description: Issued when the Virtual Machine is powered down.
 | 
				
			||||||
Data: None.
 | 
					Data: None.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example:
 | 
					2 RESET
 | 
				
			||||||
 | 
					 | 
				
			||||||
{ "event": "RESET",
 | 
					 | 
				
			||||||
    "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RESUME
 | 
					 | 
				
			||||||
------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Emitted when the Virtual Machine resumes execution.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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}
 | 
					 | 
				
			||||||
}}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
STOP
 | 
					 | 
				
			||||||
----
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Emitted when the Virtual Machine is stopped.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Data: None.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Example:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{ "event": "STOP",
 | 
					 | 
				
			||||||
    "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SUSPEND
 | 
					 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Emitted when guest enters S3 state.
 | 
					Description: Issued when the Virtual Machine is reseted.
 | 
				
			||||||
 | 
					 | 
				
			||||||
Data: None.
 | 
					Data: None.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example:
 | 
					3 STOP
 | 
				
			||||||
 | 
					 | 
				
			||||||
{ "event": "SUSPEND",
 | 
					 | 
				
			||||||
     "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SUSPEND_DISK
 | 
					 | 
				
			||||||
------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Emitted when the guest makes a request to enter S4 state.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Data: None.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Example:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{ "event": "SUSPEND_DISK",
 | 
					 | 
				
			||||||
     "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Note: QEMU shuts down when entering S4 state.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
WAKEUP
 | 
					 | 
				
			||||||
------
 | 
					------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Emitted when the guest has woken up from S3 and is running.
 | 
					Description: Issued when the Virtual Machine is stopped.
 | 
				
			||||||
 | 
					 | 
				
			||||||
Data: None.
 | 
					Data: None.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example:
 | 
					4 DEBUG
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{ "event": "WATCHDOG",
 | 
					Description: Issued when the Virtual Machine enters debug mode.
 | 
				
			||||||
     "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
 | 
					Data: None.
 | 
				
			||||||
 | 
					 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										265
									
								
								QMP/qmp-shell
									
									
									
									
									
								
							
							
						
						
									
										265
									
								
								QMP/qmp-shell
									
									
									
									
									
								
							@@ -1,8 +1,8 @@
 | 
				
			|||||||
#!/usr/bin/python
 | 
					#!/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:
 | 
					# Authors:
 | 
				
			||||||
#  Luiz Capitulino <lcapitulino@redhat.com>
 | 
					#  Luiz Capitulino <lcapitulino@redhat.com>
 | 
				
			||||||
@@ -14,246 +14,59 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# Start QEMU with:
 | 
					# Start QEMU with:
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# # qemu [...] -qmp unix:./qmp-sock,server
 | 
					# $ qemu [...] -monitor control,unix:./qmp,server
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Run the shell:
 | 
					# Run the shell:
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# $ qmp-shell ./qmp-sock
 | 
					# $ qmp-shell ./qmp
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Commands have the following format:
 | 
					# Commands have the following format:
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#    < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
 | 
					# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# For example:
 | 
					# For example:
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# (QEMU) device_add driver=e1000 id=net1
 | 
					# (QEMU) info item=network
 | 
				
			||||||
# {u'return': {}}
 | 
					 | 
				
			||||||
# (QEMU)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import qmp
 | 
					import qmp
 | 
				
			||||||
import readline
 | 
					import readline
 | 
				
			||||||
import sys
 | 
					from sys import argv,exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QMPCompleter(list):
 | 
					def shell_help():
 | 
				
			||||||
    def complete(self, text, state):
 | 
					    print 'bye  exit from the shell'
 | 
				
			||||||
        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 main():
 | 
					def main():
 | 
				
			||||||
    addr = ''
 | 
					    if len(argv) != 2:
 | 
				
			||||||
    try:
 | 
					        print 'qemu-shell <unix-socket>'
 | 
				
			||||||
        if len(sys.argv) == 2:
 | 
					        exit(1)
 | 
				
			||||||
            qemu = QMPShell(sys.argv[1])
 | 
					
 | 
				
			||||||
            addr = sys.argv[1]
 | 
					    qemu = qmp.QEMUMonitorProtocol(argv[1])
 | 
				
			||||||
        elif len(sys.argv) == 3:
 | 
					    qemu.connect()
 | 
				
			||||||
            if sys.argv[1] != '-H':
 | 
					
 | 
				
			||||||
                fail_cmdline(sys.argv[1])
 | 
					    print 'Connected!'
 | 
				
			||||||
            qemu = HMPShell(sys.argv[2])
 | 
					
 | 
				
			||||||
            addr = sys.argv[2]
 | 
					    while True:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            cmd = raw_input('(QEMU) ')
 | 
				
			||||||
 | 
					        except EOFError:
 | 
				
			||||||
 | 
					            print
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					        if cmd == '':
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        elif cmd == 'bye':
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					        elif cmd == 'help':
 | 
				
			||||||
 | 
					            shell_help()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
                fail_cmdline()
 | 
					            try:
 | 
				
			||||||
    except QMPShellBadPort:
 | 
					                resp = qemu.send(cmd)
 | 
				
			||||||
        die('bad port number in command-line')
 | 
					                if resp == None:
 | 
				
			||||||
 | 
					                    print 'Disconnected'
 | 
				
			||||||
    try:
 | 
					                    break
 | 
				
			||||||
        qemu.connect()
 | 
					                print resp
 | 
				
			||||||
    except qmp.QMPConnectError:
 | 
					            except IndexError:
 | 
				
			||||||
        die('Didn\'t get QMP greeting message')
 | 
					                print '-> command format: <command-name> ',
 | 
				
			||||||
    except qmp.QMPCapabilitiesError:
 | 
					                print '[arg-name1=arg1] ... [arg-nameN=argN]'
 | 
				
			||||||
        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()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    main()
 | 
					    main()
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										125
									
								
								QMP/qmp-spec.txt
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								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
 | 
					Right when connected the Server will issue a greeting message, which signals
 | 
				
			||||||
that the connection has been successfully established and that the Server is
 | 
					that the connection has been successfully established and that the Server is
 | 
				
			||||||
ready for capabilities negotiation (for more information refer to section
 | 
					waiting for commands.
 | 
				
			||||||
'4. Capabilities Negotiation').
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
The format is:
 | 
					The format is:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{ "QMP": { "version": json-object, "capabilities": json-array } }
 | 
					{ "QMP": { "capabilities": json-array } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 Where,
 | 
					 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
 | 
					- The "capabilities" member specify the availability of features beyond the
 | 
				
			||||||
  baseline specification
 | 
					  baseline specification
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -106,11 +103,14 @@ completed because of an error condition.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
The format is:
 | 
					The format is:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
 | 
					{ "error": { "class": json-string, "data": json-object, "desc": json-string },
 | 
				
			||||||
 | 
					  "id": json-value }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 Where,
 | 
					 Where,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- The "class" member contains the error class name (eg. "GenericError")
 | 
					- The "class" member contains the error class name (eg. "ServiceUnavailable")
 | 
				
			||||||
 | 
					- The "data" member contains specific error data and is defined in a
 | 
				
			||||||
 | 
					  per-command basis, it will be an empty json-object if the error has no data
 | 
				
			||||||
- The "desc" member is a human-readable error message. Clients should
 | 
					- The "desc" member is a human-readable error message. Clients should
 | 
				
			||||||
  not attempt to parse this message.
 | 
					  not attempt to parse this message.
 | 
				
			||||||
- The "id" member contains the transaction identification associated with
 | 
					- The "id" member contains the transaction identification associated with
 | 
				
			||||||
@@ -152,7 +152,7 @@ This section provides some examples of real QMP usage, in all of them
 | 
				
			|||||||
3.1 Server greeting
 | 
					3.1 Server greeting
 | 
				
			||||||
-------------------
 | 
					-------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
 | 
					S: {"QMP": {"capabilities": []}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
3.2 Simple 'stop' execution
 | 
					3.2 Simple 'stop' execution
 | 
				
			||||||
---------------------------
 | 
					---------------------------
 | 
				
			||||||
@@ -170,7 +170,8 @@ S: {"return": {"enabled": true, "present": true}, "id": "example"}
 | 
				
			|||||||
------------------
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
C: { "execute": }
 | 
					C: { "execute": }
 | 
				
			||||||
S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
 | 
					S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
 | 
				
			||||||
 | 
					{}}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
3.5 Powerdown event
 | 
					3.5 Powerdown event
 | 
				
			||||||
-------------------
 | 
					-------------------
 | 
				
			||||||
@@ -178,105 +179,25 @@ S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
 | 
				
			|||||||
S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
 | 
					S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
 | 
				
			||||||
"POWERDOWN"}
 | 
					"POWERDOWN"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4. Capabilities Negotiation
 | 
					4. Compatibility Considerations
 | 
				
			||||||
----------------------------
 | 
					--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When a Client successfully establishes a connection, the Server is in
 | 
					In order to achieve maximum compatibility between versions, Clients must not 
 | 
				
			||||||
Capabilities Negotiation mode.
 | 
					assume any particular:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In this mode only the 'qmp_capabilities' command is allowed to run, all
 | 
					- Size of json-objects or length of json-arrays
 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
- Order of json-object members or json-array elements
 | 
					- Order of json-object members or json-array elements
 | 
				
			||||||
- Amount of errors generated by a command, that is, new errors can be added
 | 
					- Amount of errors generated by a command, that is, new errors can be added
 | 
				
			||||||
  to any existing command in newer versions of the Server
 | 
					  to any existing command in newer versions of the Server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Of course, the Server does guarantee to send valid JSON.  But apart from
 | 
					Additionally, Clients should always:
 | 
				
			||||||
this, a Client should be "conservative in what they send, and liberal in
 | 
					 | 
				
			||||||
what they accept".
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.
 | 
					5. Recommendations to Client implementors
 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
However, we recognize that it is sometimes impossible for downstreams to
 | 
					5.1 The Server should be always started in pause mode, thus the Client is
 | 
				
			||||||
avoid modifying QMP.  Both upstream and downstream need to take care to
 | 
					    able to perform any setup procedure without the risk of race conditions
 | 
				
			||||||
preserve long-term compatibility and interoperability.
 | 
					    and related problems
 | 
				
			||||||
 | 
					 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										195
									
								
								QMP/qmp.py
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								QMP/qmp.py
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
# QEMU Monitor Protocol Python class
 | 
					# QEMU Monitor Protocol Python class
 | 
				
			||||||
# 
 | 
					# 
 | 
				
			||||||
# Copyright (C) 2009, 2010 Red Hat Inc.
 | 
					# Copyright (C) 2009 Red Hat Inc.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Authors:
 | 
					# Authors:
 | 
				
			||||||
#  Luiz Capitulino <lcapitulino@redhat.com>
 | 
					#  Luiz Capitulino <lcapitulino@redhat.com>
 | 
				
			||||||
@@ -8,9 +8,7 @@
 | 
				
			|||||||
# This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
					# This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
				
			||||||
# the COPYING file in the top-level directory.
 | 
					# the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import json
 | 
					import socket, json
 | 
				
			||||||
import errno
 | 
					 | 
				
			||||||
import socket
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QMPError(Exception):
 | 
					class QMPError(Exception):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
@@ -18,146 +16,57 @@ class QMPError(Exception):
 | 
				
			|||||||
class QMPConnectError(QMPError):
 | 
					class QMPConnectError(QMPError):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QMPCapabilitiesError(QMPError):
 | 
					 | 
				
			||||||
    pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class QEMUMonitorProtocol:
 | 
					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):
 | 
					    def connect(self):
 | 
				
			||||||
        """
 | 
					        self.sock.connect(self.filename)
 | 
				
			||||||
        Connect to the QMP Monitor and perform capabilities negotiation.
 | 
					        data = self.__json_read()
 | 
				
			||||||
 | 
					        if data == None:
 | 
				
			||||||
        @return QMP greeting dict
 | 
					            raise QMPConnectError
 | 
				
			||||||
        @raise socket.error on socket connection errors
 | 
					        if not data.has_key('QMP'):
 | 
				
			||||||
        @raise QMPConnectError if the greeting is not received
 | 
					            raise QMPConnectError
 | 
				
			||||||
        @raise QMPCapabilitiesError if fails to negotiate capabilities
 | 
					        return data['QMP']['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 = []
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def close(self):
 | 
					    def close(self):
 | 
				
			||||||
        self.__sock.close()
 | 
					        self.sock.close()
 | 
				
			||||||
        self.__sockfile.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_FILNMLEN	14	/* # characters in a file name		*/
 | 
				
			||||||
#define E_DIMNUM	4	/* # array dimensions in auxiliary entry */
 | 
					#define E_DIMNUM	4	/* # array dimensions in auxiliary entry */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct QEMU_PACKED external_syment
 | 
					struct __attribute__((packed)) external_syment
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  union {
 | 
					  union {
 | 
				
			||||||
    char e_name[E_SYMNMLEN];
 | 
					    char e_name[E_SYMNMLEN];
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								acl.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								acl.c
									
									
									
									
									
								
							@@ -24,6 +24,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					#include "sysemu.h"
 | 
				
			||||||
#include "acl.h"
 | 
					#include "acl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_FNMATCH
 | 
					#ifdef CONFIG_FNMATCH
 | 
				
			||||||
@@ -55,8 +56,8 @@ qemu_acl *qemu_acl_init(const char *aclname)
 | 
				
			|||||||
    if (acl)
 | 
					    if (acl)
 | 
				
			||||||
        return acl;
 | 
					        return acl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    acl = g_malloc(sizeof(*acl));
 | 
					    acl = qemu_malloc(sizeof(*acl));
 | 
				
			||||||
    acl->aclname = g_strdup(aclname);
 | 
					    acl->aclname = qemu_strdup(aclname);
 | 
				
			||||||
    /* Deny by default, so there is no window of "open
 | 
					    /* Deny by default, so there is no window of "open
 | 
				
			||||||
     * access" between QEMU starting, and the user setting
 | 
					     * access" between QEMU starting, and the user setting
 | 
				
			||||||
     * up ACLs in the monitor */
 | 
					     * up ACLs in the monitor */
 | 
				
			||||||
@@ -65,7 +66,7 @@ qemu_acl *qemu_acl_init(const char *aclname)
 | 
				
			|||||||
    acl->nentries = 0;
 | 
					    acl->nentries = 0;
 | 
				
			||||||
    QTAILQ_INIT(&acl->entries);
 | 
					    QTAILQ_INIT(&acl->entries);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    acls = g_realloc(acls, sizeof(*acls) * (nacls +1));
 | 
					    acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1));
 | 
				
			||||||
    acls[nacls] = acl;
 | 
					    acls[nacls] = acl;
 | 
				
			||||||
    nacls++;
 | 
					    nacls++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,13 +96,13 @@ int qemu_acl_party_is_allowed(qemu_acl *acl,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void qemu_acl_reset(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
 | 
					    /* Put back to deny by default, so there is no window
 | 
				
			||||||
     * of "open access" while the user re-initializes the
 | 
					     * of "open access" while the user re-initializes the
 | 
				
			||||||
     * access control list */
 | 
					     * access control list */
 | 
				
			||||||
    acl->defaultDeny = 1;
 | 
					    acl->defaultDeny = 1;
 | 
				
			||||||
    QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) {
 | 
					    QTAILQ_FOREACH(entry, &acl->entries, next) {
 | 
				
			||||||
        QTAILQ_REMOVE(&acl->entries, entry, next);
 | 
					        QTAILQ_REMOVE(&acl->entries, entry, next);
 | 
				
			||||||
        free(entry->match);
 | 
					        free(entry->match);
 | 
				
			||||||
        free(entry);
 | 
					        free(entry);
 | 
				
			||||||
@@ -116,8 +117,8 @@ int qemu_acl_append(qemu_acl *acl,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    qemu_acl_entry *entry;
 | 
					    qemu_acl_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    entry = g_malloc(sizeof(*entry));
 | 
					    entry = qemu_malloc(sizeof(*entry));
 | 
				
			||||||
    entry->match = g_strdup(match);
 | 
					    entry->match = qemu_strdup(match);
 | 
				
			||||||
    entry->deny = deny;
 | 
					    entry->deny = deny;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QTAILQ_INSERT_TAIL(&acl->entries, entry, next);
 | 
					    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);
 | 
					        return qemu_acl_append(acl, deny, match);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    entry = g_malloc(sizeof(*entry));
 | 
					    entry = qemu_malloc(sizeof(*entry));
 | 
				
			||||||
    entry->match = g_strdup(match);
 | 
					    entry->match = qemu_strdup(match);
 | 
				
			||||||
    entry->deny = deny;
 | 
					    entry->deny = deny;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QTAILQ_FOREACH(tmp, &acl->entries, next) {
 | 
					    QTAILQ_FOREACH(tmp, &acl->entries, next) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										178
									
								
								aio.c
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								aio.c
									
									
									
									
									
								
							@@ -9,8 +9,6 @@
 | 
				
			|||||||
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
					 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
				
			||||||
 * the COPYING file in the top-level directory.
 | 
					 * 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 "qemu-common.h"
 | 
				
			||||||
@@ -35,6 +33,7 @@ struct AioHandler
 | 
				
			|||||||
    IOHandler *io_read;
 | 
					    IOHandler *io_read;
 | 
				
			||||||
    IOHandler *io_write;
 | 
					    IOHandler *io_write;
 | 
				
			||||||
    AioFlushHandler *io_flush;
 | 
					    AioFlushHandler *io_flush;
 | 
				
			||||||
 | 
					    AioProcessQueue *io_process_queue;
 | 
				
			||||||
    int deleted;
 | 
					    int deleted;
 | 
				
			||||||
    void *opaque;
 | 
					    void *opaque;
 | 
				
			||||||
    QLIST_ENTRY(AioHandler) node;
 | 
					    QLIST_ENTRY(AioHandler) node;
 | 
				
			||||||
@@ -57,6 +56,7 @@ int qemu_aio_set_fd_handler(int fd,
 | 
				
			|||||||
                            IOHandler *io_read,
 | 
					                            IOHandler *io_read,
 | 
				
			||||||
                            IOHandler *io_write,
 | 
					                            IOHandler *io_write,
 | 
				
			||||||
                            AioFlushHandler *io_flush,
 | 
					                            AioFlushHandler *io_flush,
 | 
				
			||||||
 | 
					                            AioProcessQueue *io_process_queue,
 | 
				
			||||||
                            void *opaque)
 | 
					                            void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AioHandler *node;
 | 
					    AioHandler *node;
 | 
				
			||||||
@@ -75,13 +75,13 @@ int qemu_aio_set_fd_handler(int fd,
 | 
				
			|||||||
                 * releasing the walking_handlers lock.
 | 
					                 * releasing the walking_handlers lock.
 | 
				
			||||||
                 */
 | 
					                 */
 | 
				
			||||||
                QLIST_REMOVE(node, node);
 | 
					                QLIST_REMOVE(node, node);
 | 
				
			||||||
                g_free(node);
 | 
					                qemu_free(node);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        if (node == NULL) {
 | 
					        if (node == NULL) {
 | 
				
			||||||
            /* Alloc and insert if it's not already there */
 | 
					            /* Alloc and insert if it's not already there */
 | 
				
			||||||
            node = g_malloc0(sizeof(AioHandler));
 | 
					            node = qemu_mallocz(sizeof(AioHandler));
 | 
				
			||||||
            node->fd = fd;
 | 
					            node->fd = fd;
 | 
				
			||||||
            QLIST_INSERT_HEAD(&aio_handlers, node, node);
 | 
					            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_read = io_read;
 | 
				
			||||||
        node->io_write = io_write;
 | 
					        node->io_write = io_write;
 | 
				
			||||||
        node->io_flush = io_flush;
 | 
					        node->io_flush = io_flush;
 | 
				
			||||||
 | 
					        node->io_process_queue = io_process_queue;
 | 
				
			||||||
        node->opaque = opaque;
 | 
					        node->opaque = opaque;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -99,96 +100,131 @@ int qemu_aio_set_fd_handler(int fd,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void qemu_aio_flush(void)
 | 
					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;
 | 
					    AioHandler *node;
 | 
				
			||||||
    fd_set rdfds, wrfds;
 | 
					    int ret = 0;
 | 
				
			||||||
    int max_fd = -1;
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
    bool busy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
     * 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).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    if (qemu_bh_poll()) {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    walking_handlers = 1;
 | 
					    walking_handlers = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FD_ZERO(&rdfds);
 | 
					 | 
				
			||||||
    FD_ZERO(&wrfds);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* fill fd sets */
 | 
					 | 
				
			||||||
    busy = false;
 | 
					 | 
				
			||||||
    QLIST_FOREACH(node, &aio_handlers, node) {
 | 
					    QLIST_FOREACH(node, &aio_handlers, node) {
 | 
				
			||||||
        /* If there aren't pending AIO operations, don't invoke callbacks.
 | 
					        if (node->io_process_queue) {
 | 
				
			||||||
         * Otherwise, if there are no AIO requests, qemu_aio_wait() would
 | 
					            if (node->io_process_queue(node->opaque)) {
 | 
				
			||||||
         * wait indefinitely.
 | 
					                ret = 1;
 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        if (node->io_flush) {
 | 
					 | 
				
			||||||
            if (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);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (!node->deleted && node->io_write) {
 | 
					 | 
				
			||||||
            FD_SET(node->fd, &wrfds);
 | 
					 | 
				
			||||||
            max_fd = MAX(max_fd, node->fd + 1);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    walking_handlers = 0;
 | 
					    walking_handlers = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* No AIO operations?  Get us out of here */
 | 
					    return ret;
 | 
				
			||||||
    if (!busy) {
 | 
					}
 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* wait until next event */
 | 
					void qemu_aio_wait(void)
 | 
				
			||||||
    ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (qemu_bh_poll())
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * If there are callbacks left that have been queued, we need to call then.
 | 
				
			||||||
 | 
					     * Return afterwards to avoid waiting needlessly in select().
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (qemu_aio_process_queue())
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        AioHandler *node;
 | 
				
			||||||
 | 
					        fd_set rdfds, wrfds;
 | 
				
			||||||
 | 
					        int max_fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* if we have any readable fds, dispatch event */
 | 
					 | 
				
			||||||
    if (ret > 0) {
 | 
					 | 
				
			||||||
        walking_handlers = 1;
 | 
					        walking_handlers = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* we have to walk very carefully in case
 | 
					        FD_ZERO(&rdfds);
 | 
				
			||||||
         * qemu_aio_set_fd_handler is called while we're walking */
 | 
					        FD_ZERO(&wrfds);
 | 
				
			||||||
        node = QLIST_FIRST(&aio_handlers);
 | 
					 | 
				
			||||||
        while (node) {
 | 
					 | 
				
			||||||
            AioHandler *tmp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!node->deleted &&
 | 
					        /* fill fd sets */
 | 
				
			||||||
                FD_ISSET(node->fd, &rdfds) &&
 | 
					        QLIST_FOREACH(node, &aio_handlers, node) {
 | 
				
			||||||
                node->io_read) {
 | 
					            /* If there aren't pending AIO operations, don't invoke callbacks.
 | 
				
			||||||
                node->io_read(node->opaque);
 | 
					             * Otherwise, if there are no AIO requests, qemu_aio_wait() would
 | 
				
			||||||
 | 
					             * wait indefinitely.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            if (node->io_flush && node->io_flush(node->opaque) == 0)
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!node->deleted && node->io_read) {
 | 
				
			||||||
 | 
					                FD_SET(node->fd, &rdfds);
 | 
				
			||||||
 | 
					                max_fd = MAX(max_fd, node->fd + 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (!node->deleted &&
 | 
					            if (!node->deleted && node->io_write) {
 | 
				
			||||||
                FD_ISSET(node->fd, &wrfds) &&
 | 
					                FD_SET(node->fd, &wrfds);
 | 
				
			||||||
                node->io_write) {
 | 
					                max_fd = MAX(max_fd, node->fd + 1);
 | 
				
			||||||
                node->io_write(node->opaque);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            tmp = node;
 | 
					 | 
				
			||||||
            node = QLIST_NEXT(node, node);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (tmp->deleted) {
 | 
					 | 
				
			||||||
                QLIST_REMOVE(tmp, node);
 | 
					 | 
				
			||||||
                g_free(tmp);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        walking_handlers = 0;
 | 
					        walking_handlers = 0;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return true;
 | 
					        /* No AIO operations?  Get us out of here */
 | 
				
			||||||
 | 
					        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) {
 | 
				
			||||||
 | 
					            walking_handlers = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* we have to walk very carefully in case
 | 
				
			||||||
 | 
					             * qemu_aio_set_fd_handler is called while we're walking */
 | 
				
			||||||
 | 
					            node = QLIST_FIRST(&aio_handlers);
 | 
				
			||||||
 | 
					            while (node) {
 | 
				
			||||||
 | 
					                AioHandler *tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!node->deleted &&
 | 
				
			||||||
 | 
					                    FD_ISSET(node->fd, &rdfds) &&
 | 
				
			||||||
 | 
					                    node->io_read) {
 | 
				
			||||||
 | 
					                    node->io_read(node->opaque);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (!node->deleted &&
 | 
				
			||||||
 | 
					                    FD_ISSET(node->fd, &wrfds) &&
 | 
				
			||||||
 | 
					                    node->io_write) {
 | 
				
			||||||
 | 
					                    node->io_write(node->opaque);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                tmp = node;
 | 
				
			||||||
 | 
					                node = QLIST_NEXT(node, node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (tmp->deleted) {
 | 
				
			||||||
 | 
					                    QLIST_REMOVE(tmp, node);
 | 
				
			||||||
 | 
					                    qemu_free(tmp);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            walking_handlers = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } while (ret == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,9 +22,6 @@ along with this file; see the file COPYING.  If not, see
 | 
				
			|||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include "dis-asm.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.  */
 | 
					/* The opcode table is an array of struct alpha_opcode.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct alpha_opcode
 | 
					struct alpha_opcode
 | 
				
			||||||
@@ -238,6 +235,10 @@ extern const unsigned alpha_num_operands;
 | 
				
			|||||||
#define AXP_REG_SP	30
 | 
					#define AXP_REG_SP	30
 | 
				
			||||||
#define AXP_REG_ZERO	31
 | 
					#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 {
 | 
					enum bfd_reloc_code_real {
 | 
				
			||||||
    BFD_RELOC_23_PCREL_S2,
 | 
					    BFD_RELOC_23_PCREL_S2,
 | 
				
			||||||
    BFD_RELOC_ALPHA_HINT
 | 
					    BFD_RELOC_ALPHA_HINT
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1093
									
								
								arch_init.c
									
									
									
									
									
								
							
							
						
						
									
										1093
									
								
								arch_init.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										39
									
								
								arch_init.h
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								arch_init.h
									
									
									
									
									
								
							@@ -1,39 +0,0 @@
 | 
				
			|||||||
#ifndef QEMU_ARCH_INIT_H
 | 
					 | 
				
			||||||
#define QEMU_ARCH_INIT_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "qmp-commands.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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,
 | 
					 | 
				
			||||||
    QEMU_ARCH_OPENRISC = 8192,
 | 
					 | 
				
			||||||
    QEMU_ARCH_UNICORE32 = 0x4000,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CpuDefinitionInfoList GCC_WEAK_DECL *arch_query_cpu_definitions(Error **errp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
							
								
								
									
										61
									
								
								arm-dis.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								arm-dis.c
									
									
									
									
									
								
							@@ -60,8 +60,10 @@
 | 
				
			|||||||
#define FPU_VFP_EXT_V3	 0
 | 
					#define FPU_VFP_EXT_V3	 0
 | 
				
			||||||
#define FPU_NEON_EXT_V1	 0
 | 
					#define FPU_NEON_EXT_V1	 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int floatformat_ieee_single_little;
 | 
				
			||||||
/* Assume host uses ieee float.  */
 | 
					/* 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 {
 | 
					    union {
 | 
				
			||||||
        uint32_t i;
 | 
					        uint32_t i;
 | 
				
			||||||
@@ -1587,7 +1589,7 @@ arm_decode_bitfield (const char *ptr, unsigned long insn,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					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)
 | 
							  int print_shift)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  func (stream, "%s", arm_regnames[given & 0xf]);
 | 
					  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.
 | 
					/* 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.  */
 | 
					   recognised coprocessor instruction.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bfd_boolean
 | 
					static bfd_boolean
 | 
				
			||||||
@@ -1633,7 +1635,7 @@ print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  const struct opcode32 *insn;
 | 
					  const struct opcode32 *insn;
 | 
				
			||||||
  void *stream = info->stream;
 | 
					  void *stream = info->stream;
 | 
				
			||||||
  fprintf_function func = info->fprintf_func;
 | 
					  fprintf_ftype func = info->fprintf_func;
 | 
				
			||||||
  unsigned long mask;
 | 
					  unsigned long mask;
 | 
				
			||||||
  unsigned long value;
 | 
					  unsigned long value;
 | 
				
			||||||
  int cond;
 | 
					  int cond;
 | 
				
			||||||
@@ -2127,7 +2129,7 @@ static void
 | 
				
			|||||||
print_arm_address (bfd_vma pc, struct disassemble_info *info, long given)
 | 
					print_arm_address (bfd_vma pc, struct disassemble_info *info, long given)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  void *stream = info->stream;
 | 
					  void *stream = info->stream;
 | 
				
			||||||
  fprintf_function func = info->fprintf_func;
 | 
					  fprintf_ftype func = info->fprintf_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (((given & 0x000f0000) == 0x000f0000)
 | 
					  if (((given & 0x000f0000) == 0x000f0000)
 | 
				
			||||||
      && ((given & 0x02000000) == 0))
 | 
					      && ((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.
 | 
					/* 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.  */
 | 
					   recognised neon instruction.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bfd_boolean
 | 
					static bfd_boolean
 | 
				
			||||||
@@ -2222,7 +2224,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  const struct opcode32 *insn;
 | 
					  const struct opcode32 *insn;
 | 
				
			||||||
  void *stream = info->stream;
 | 
					  void *stream = info->stream;
 | 
				
			||||||
  fprintf_function func = info->fprintf_func;
 | 
					  fprintf_ftype func = info->fprintf_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (thumb)
 | 
					  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>",
 | 
								    func (stream, "<illegal constant %.8x:%x:%x>",
 | 
				
			||||||
                                  bits, cmode, op);
 | 
					                                  bits, cmode, op);
 | 
				
			||||||
 | 
					                            size = 32;
 | 
				
			||||||
			    break;
 | 
								    break;
 | 
				
			||||||
			  }
 | 
								  }
 | 
				
			||||||
                        switch (size)
 | 
					                        switch (size)
 | 
				
			||||||
@@ -2540,7 +2543,9 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
 | 
				
			|||||||
                                valbytes[2] = (value >> 16) & 0xff;
 | 
					                                valbytes[2] = (value >> 16) & 0xff;
 | 
				
			||||||
                                valbytes[3] = (value >> 24) & 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,
 | 
					                                func (stream, "#%.7g\t; 0x%.8lx", fvalue,
 | 
				
			||||||
                                      value);
 | 
					                                      value);
 | 
				
			||||||
@@ -2676,7 +2681,7 @@ print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  const struct opcode32 *insn;
 | 
					  const struct opcode32 *insn;
 | 
				
			||||||
  void *stream = info->stream;
 | 
					  void *stream = info->stream;
 | 
				
			||||||
  fprintf_function func = info->fprintf_func;
 | 
					  fprintf_ftype func = info->fprintf_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (print_insn_coprocessor (pc, info, given, false))
 | 
					  if (print_insn_coprocessor (pc, info, given, false))
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
@@ -3036,7 +3041,7 @@ print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  const struct opcode16 *insn;
 | 
					  const struct opcode16 *insn;
 | 
				
			||||||
  void *stream = info->stream;
 | 
					  void *stream = info->stream;
 | 
				
			||||||
  fprintf_function func = info->fprintf_func;
 | 
					  fprintf_ftype func = info->fprintf_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (insn = thumb_opcodes; insn->assembler; insn++)
 | 
					  for (insn = thumb_opcodes; insn->assembler; insn++)
 | 
				
			||||||
    if ((given & insn->mask) == insn->value)
 | 
					    if ((given & insn->mask) == insn->value)
 | 
				
			||||||
@@ -3148,14 +3153,14 @@ print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
				
			|||||||
		      if (started)
 | 
							      if (started)
 | 
				
			||||||
			func (stream, ", ");
 | 
								func (stream, ", ");
 | 
				
			||||||
		      started = 1;
 | 
							      started = 1;
 | 
				
			||||||
		      func (stream, "%s", arm_regnames[14] /* "lr" */);
 | 
							      func (stream, arm_regnames[14] /* "lr" */);
 | 
				
			||||||
		    }
 | 
							    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		  if (domaskpc)
 | 
							  if (domaskpc)
 | 
				
			||||||
		    {
 | 
							    {
 | 
				
			||||||
		      if (started)
 | 
							      if (started)
 | 
				
			||||||
			func (stream, ", ");
 | 
								func (stream, ", ");
 | 
				
			||||||
		      func (stream, "%s", arm_regnames[15] /* "pc" */);
 | 
							      func (stream, arm_regnames[15] /* "pc" */);
 | 
				
			||||||
		    }
 | 
							    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		  func (stream, "}");
 | 
							  func (stream, "}");
 | 
				
			||||||
@@ -3312,7 +3317,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  const struct opcode32 *insn;
 | 
					  const struct opcode32 *insn;
 | 
				
			||||||
  void *stream = info->stream;
 | 
					  void *stream = info->stream;
 | 
				
			||||||
  fprintf_function func = info->fprintf_func;
 | 
					  fprintf_ftype func = info->fprintf_func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (print_insn_coprocessor (pc, info, given, true))
 | 
					  if (print_insn_coprocessor (pc, info, given, true))
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
@@ -3698,7 +3703,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
				
			|||||||
		  }
 | 
							  }
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
		  {
 | 
							  {
 | 
				
			||||||
		    func (stream, "%s", psr_name (given & 0xff));
 | 
							    func (stream, psr_name (given & 0xff));
 | 
				
			||||||
		  }
 | 
							  }
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3706,7 +3711,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 | 
				
			|||||||
		if ((given & 0xff) == 0)
 | 
							if ((given & 0xff) == 0)
 | 
				
			||||||
		  func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C');
 | 
							  func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C');
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
		  func (stream, "%s", psr_name (given & 0xff));
 | 
							  func (stream, psr_name (given & 0xff));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	      case '0': case '1': case '2': case '3': case '4':
 | 
						      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;
 | 
						    n = last_mapping_sym - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  /* No mapping symbol found at this address.  Look backwards
 | 
						  /* No mapping symbol found at this address.  Look backwards
 | 
				
			||||||
	     for a preceding one.  */
 | 
						     for a preceeding one.  */
 | 
				
			||||||
	  for (; n >= 0; n--)
 | 
						  for (; n >= 0; n--)
 | 
				
			||||||
	    {
 | 
						    {
 | 
				
			||||||
	      if (get_sym_code_type (info, n, &type))
 | 
						      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.  */
 | 
					       addresses, since the addend is not currently pc-relative.  */
 | 
				
			||||||
    pc = 0;
 | 
					    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);
 | 
					  printer (pc, info, given);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (is_thumb)
 | 
					  if (is_thumb)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,30 +33,30 @@
 | 
				
			|||||||
#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
 | 
					#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					#include "sysemu.h"
 | 
				
			||||||
#include "gdbstub.h"
 | 
					#include "gdbstub.h"
 | 
				
			||||||
#include "hw/arm-misc.h"
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TARGET_SYS_OPEN        0x01
 | 
					#define SYS_OPEN        0x01
 | 
				
			||||||
#define TARGET_SYS_CLOSE       0x02
 | 
					#define SYS_CLOSE       0x02
 | 
				
			||||||
#define TARGET_SYS_WRITEC      0x03
 | 
					#define SYS_WRITEC      0x03
 | 
				
			||||||
#define TARGET_SYS_WRITE0      0x04
 | 
					#define SYS_WRITE0      0x04
 | 
				
			||||||
#define TARGET_SYS_WRITE       0x05
 | 
					#define SYS_WRITE       0x05
 | 
				
			||||||
#define TARGET_SYS_READ        0x06
 | 
					#define SYS_READ        0x06
 | 
				
			||||||
#define TARGET_SYS_READC       0x07
 | 
					#define SYS_READC       0x07
 | 
				
			||||||
#define TARGET_SYS_ISTTY       0x09
 | 
					#define SYS_ISTTY       0x09
 | 
				
			||||||
#define TARGET_SYS_SEEK        0x0a
 | 
					#define SYS_SEEK        0x0a
 | 
				
			||||||
#define TARGET_SYS_FLEN        0x0c
 | 
					#define SYS_FLEN        0x0c
 | 
				
			||||||
#define TARGET_SYS_TMPNAM      0x0d
 | 
					#define SYS_TMPNAM      0x0d
 | 
				
			||||||
#define TARGET_SYS_REMOVE      0x0e
 | 
					#define SYS_REMOVE      0x0e
 | 
				
			||||||
#define TARGET_SYS_RENAME      0x0f
 | 
					#define SYS_RENAME      0x0f
 | 
				
			||||||
#define TARGET_SYS_CLOCK       0x10
 | 
					#define SYS_CLOCK       0x10
 | 
				
			||||||
#define TARGET_SYS_TIME        0x11
 | 
					#define SYS_TIME        0x11
 | 
				
			||||||
#define TARGET_SYS_SYSTEM      0x12
 | 
					#define SYS_SYSTEM      0x12
 | 
				
			||||||
#define TARGET_SYS_ERRNO       0x13
 | 
					#define SYS_ERRNO       0x13
 | 
				
			||||||
#define TARGET_SYS_GET_CMDLINE 0x15
 | 
					#define SYS_GET_CMDLINE 0x15
 | 
				
			||||||
#define TARGET_SYS_HEAPINFO    0x16
 | 
					#define SYS_HEAPINFO    0x16
 | 
				
			||||||
#define TARGET_SYS_EXIT        0x18
 | 
					#define SYS_EXIT        0x18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef O_BINARY
 | 
					#ifndef O_BINARY
 | 
				
			||||||
#define O_BINARY 0
 | 
					#define O_BINARY 0
 | 
				
			||||||
@@ -108,7 +108,7 @@ static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
 | 
				
			|||||||
    return code;
 | 
					    return code;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#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;
 | 
					    return code;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -122,7 +122,7 @@ static target_ulong arm_semi_syscall_len;
 | 
				
			|||||||
static target_ulong syscall_err;
 | 
					static target_ulong syscall_err;
 | 
				
			||||||
#endif
 | 
					#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
 | 
					#ifdef CONFIG_USER_ONLY
 | 
				
			||||||
    TaskState *ts = env->opaque;
 | 
					    TaskState *ts = env->opaque;
 | 
				
			||||||
@@ -138,11 +138,11 @@ static void arm_semi_cb(CPUARMState *env, target_ulong ret, target_ulong err)
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        /* Fixup syscalls that use nonstardard return conventions.  */
 | 
					        /* Fixup syscalls that use nonstardard return conventions.  */
 | 
				
			||||||
        switch (env->regs[0]) {
 | 
					        switch (env->regs[0]) {
 | 
				
			||||||
        case TARGET_SYS_WRITE:
 | 
					        case SYS_WRITE:
 | 
				
			||||||
        case TARGET_SYS_READ:
 | 
					        case SYS_READ:
 | 
				
			||||||
            env->regs[0] = arm_semi_syscall_len - ret;
 | 
					            env->regs[0] = arm_semi_syscall_len - ret;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case TARGET_SYS_SEEK:
 | 
					        case SYS_SEEK:
 | 
				
			||||||
            env->regs[0] = 0;
 | 
					            env->regs[0] = 0;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
@@ -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 size is always stored in big-endian order, extract
 | 
				
			||||||
       the value. We assume the size always fit in 32 bits.  */
 | 
					       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;					\
 | 
					    __arg;					\
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
 | 
					#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;
 | 
					    target_ulong args;
 | 
				
			||||||
    char * s;
 | 
					    char * s;
 | 
				
			||||||
@@ -184,42 +184,41 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
#ifdef CONFIG_USER_ONLY
 | 
					#ifdef CONFIG_USER_ONLY
 | 
				
			||||||
    TaskState *ts = env->opaque;
 | 
					    TaskState *ts = env->opaque;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    CPUARMState *ts = env;
 | 
					    CPUState *ts = env;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nr = env->regs[0];
 | 
					    nr = env->regs[0];
 | 
				
			||||||
    args = env->regs[1];
 | 
					    args = env->regs[1];
 | 
				
			||||||
    switch (nr) {
 | 
					    switch (nr) {
 | 
				
			||||||
    case TARGET_SYS_OPEN:
 | 
					    case SYS_OPEN:
 | 
				
			||||||
        if (!(s = lock_user_string(ARG(0))))
 | 
					        if (!(s = lock_user_string(ARG(0))))
 | 
				
			||||||
            /* FIXME - should this error code be -TARGET_EFAULT ? */
 | 
					            /* FIXME - should this error code be -TARGET_EFAULT ? */
 | 
				
			||||||
            return (uint32_t)-1;
 | 
					            return (uint32_t)-1;
 | 
				
			||||||
        if (ARG(1) >= 12) {
 | 
					        if (ARG(1) >= 12)
 | 
				
			||||||
            unlock_user(s, ARG(0), 0);
 | 
					 | 
				
			||||||
            return (uint32_t)-1;
 | 
					            return (uint32_t)-1;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (strcmp(s, ":tt") == 0) {
 | 
					        if (strcmp(s, ":tt") == 0) {
 | 
				
			||||||
            int result_fileno = ARG(1) < 4 ? STDIN_FILENO : STDOUT_FILENO;
 | 
					            if (ARG(1) < 4)
 | 
				
			||||||
            unlock_user(s, ARG(0), 0);
 | 
					                return STDIN_FILENO;
 | 
				
			||||||
            return result_fileno;
 | 
					            else
 | 
				
			||||||
 | 
					                return STDOUT_FILENO;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
 | 
					            gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
 | 
				
			||||||
			   (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
 | 
								   (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
 | 
				
			||||||
            ret = env->regs[0];
 | 
					            return env->regs[0];
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
 | 
					            ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        unlock_user(s, ARG(0), 0);
 | 
					        unlock_user(s, ARG(0), 0);
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    case TARGET_SYS_CLOSE:
 | 
					    case SYS_CLOSE:
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
 | 
					            gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
 | 
				
			||||||
            return env->regs[0];
 | 
					            return env->regs[0];
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            return set_swi_errno(ts, close(ARG(0)));
 | 
					            return set_swi_errno(ts, close(ARG(0)));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_WRITEC:
 | 
					    case SYS_WRITEC:
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          char c;
 | 
					          char c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -234,7 +233,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
                return write(STDERR_FILENO, &c, 1);
 | 
					                return write(STDERR_FILENO, &c, 1);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_WRITE0:
 | 
					    case SYS_WRITE0:
 | 
				
			||||||
        if (!(s = lock_user_string(args)))
 | 
					        if (!(s = lock_user_string(args)))
 | 
				
			||||||
            /* FIXME - should this error code be -TARGET_EFAULT ? */
 | 
					            /* FIXME - should this error code be -TARGET_EFAULT ? */
 | 
				
			||||||
            return (uint32_t)-1;
 | 
					            return (uint32_t)-1;
 | 
				
			||||||
@@ -247,7 +246,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        unlock_user(s, args, 0);
 | 
					        unlock_user(s, args, 0);
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    case TARGET_SYS_WRITE:
 | 
					    case SYS_WRITE:
 | 
				
			||||||
        len = ARG(2);
 | 
					        len = ARG(2);
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            arm_semi_syscall_len = len;
 | 
					            arm_semi_syscall_len = len;
 | 
				
			||||||
@@ -263,7 +262,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
            return len - ret;
 | 
					            return len - ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_READ:
 | 
					    case SYS_READ:
 | 
				
			||||||
        len = ARG(2);
 | 
					        len = ARG(2);
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            arm_semi_syscall_len = len;
 | 
					            arm_semi_syscall_len = len;
 | 
				
			||||||
@@ -281,17 +280,17 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
            return len - ret;
 | 
					            return len - ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_READC:
 | 
					    case SYS_READC:
 | 
				
			||||||
       /* XXX: Read from debug console. Not implemented.  */
 | 
					       /* XXX: Read from debug cosole. Not implemented.  */
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    case TARGET_SYS_ISTTY:
 | 
					    case SYS_ISTTY:
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
 | 
					            gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
 | 
				
			||||||
            return env->regs[0];
 | 
					            return env->regs[0];
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            return isatty(ARG(0));
 | 
					            return isatty(ARG(0));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_SEEK:
 | 
					    case SYS_SEEK:
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1));
 | 
					            gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1));
 | 
				
			||||||
            return env->regs[0];
 | 
					            return env->regs[0];
 | 
				
			||||||
@@ -301,7 +300,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
              return -1;
 | 
					              return -1;
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_FLEN:
 | 
					    case SYS_FLEN:
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
 | 
					            gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
 | 
				
			||||||
			   ARG(0), env->regs[13]-64);
 | 
								   ARG(0), env->regs[13]-64);
 | 
				
			||||||
@@ -313,10 +312,10 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
            return buf.st_size;
 | 
					            return buf.st_size;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_TMPNAM:
 | 
					    case SYS_TMPNAM:
 | 
				
			||||||
        /* XXX: Not implemented.  */
 | 
					        /* XXX: Not implemented.  */
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    case TARGET_SYS_REMOVE:
 | 
					    case SYS_REMOVE:
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
 | 
					            gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
 | 
				
			||||||
            ret = env->regs[0];
 | 
					            ret = env->regs[0];
 | 
				
			||||||
@@ -328,7 +327,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
            unlock_user(s, ARG(0), 0);
 | 
					            unlock_user(s, ARG(0), 0);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    case TARGET_SYS_RENAME:
 | 
					    case SYS_RENAME:
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
 | 
					            gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
 | 
				
			||||||
                           ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1);
 | 
					                           ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1);
 | 
				
			||||||
@@ -348,11 +347,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
                unlock_user(s, ARG(0), 0);
 | 
					                unlock_user(s, ARG(0), 0);
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_CLOCK:
 | 
					    case SYS_CLOCK:
 | 
				
			||||||
        return clock() / (CLOCKS_PER_SEC / 100);
 | 
					        return clock() / (CLOCKS_PER_SEC / 100);
 | 
				
			||||||
    case TARGET_SYS_TIME:
 | 
					    case SYS_TIME:
 | 
				
			||||||
        return set_swi_errno(ts, time(NULL));
 | 
					        return set_swi_errno(ts, time(NULL));
 | 
				
			||||||
    case TARGET_SYS_SYSTEM:
 | 
					    case SYS_SYSTEM:
 | 
				
			||||||
        if (use_gdb_syscalls()) {
 | 
					        if (use_gdb_syscalls()) {
 | 
				
			||||||
            gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
 | 
					            gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
 | 
				
			||||||
            return env->regs[0];
 | 
					            return env->regs[0];
 | 
				
			||||||
@@ -364,96 +363,57 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
            unlock_user(s, ARG(0), 0);
 | 
					            unlock_user(s, ARG(0), 0);
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_ERRNO:
 | 
					    case SYS_ERRNO:
 | 
				
			||||||
#ifdef CONFIG_USER_ONLY
 | 
					#ifdef CONFIG_USER_ONLY
 | 
				
			||||||
        return ts->swi_errno;
 | 
					        return ts->swi_errno;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        return syscall_err;
 | 
					        return syscall_err;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    case TARGET_SYS_GET_CMDLINE:
 | 
					    case SYS_GET_CMDLINE:
 | 
				
			||||||
 | 
					#ifdef CONFIG_USER_ONLY
 | 
				
			||||||
 | 
					        /* Build a commandline from the original argv.  */
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            /* Build a command-line from the original argv.
 | 
					            char **arg = ts->info->host_argv;
 | 
				
			||||||
             *
 | 
					            int len = ARG(1);
 | 
				
			||||||
             * The inputs are:
 | 
					            /* lock the buffer on the ARM side */
 | 
				
			||||||
             *     * ARG(0), pointer to a buffer of at least the size
 | 
					            char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
 | 
				
			||||||
             *               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 *output_buffer;
 | 
					            if (!cmdline_buffer)
 | 
				
			||||||
            size_t input_size = ARG(1);
 | 
					                /* FIXME - should this error code be -TARGET_EFAULT ? */
 | 
				
			||||||
            size_t output_size;
 | 
					                return (uint32_t)-1;
 | 
				
			||||||
            int status = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* Compute the size of the output string.  */
 | 
					            s = cmdline_buffer;
 | 
				
			||||||
#if !defined(CONFIG_USER_ONLY)
 | 
					            while (*arg && len > 2) {
 | 
				
			||||||
            output_size = strlen(ts->boot_info->kernel_filename)
 | 
					                int n = strlen(*arg);
 | 
				
			||||||
                        + 1  /* Separating space.  */
 | 
					 | 
				
			||||||
                        + strlen(ts->boot_info->kernel_cmdline)
 | 
					 | 
				
			||||||
                        + 1; /* Terminating null byte.  */
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
            unsigned int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            output_size = ts->info->arg_end - ts->info->arg_start;
 | 
					                if (s != cmdline_buffer) {
 | 
				
			||||||
            if (!output_size) {
 | 
					                    *(s++) = ' ';
 | 
				
			||||||
                /* We special-case the "empty command line" case (argc==0).
 | 
					                    len--;
 | 
				
			||||||
                   Just provide the terminating 0. */
 | 
					 | 
				
			||||||
                output_size = 1;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (output_size > input_size) {
 | 
					 | 
				
			||||||
                 /* Not enough space to store command-line arguments.  */
 | 
					 | 
				
			||||||
                return -1;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /* 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] = ' ';
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                if (n >= len)
 | 
				
			||||||
 | 
					                    n = len - 1;
 | 
				
			||||||
 | 
					                memcpy(s, *arg, n);
 | 
				
			||||||
 | 
					                s += n;
 | 
				
			||||||
 | 
					                len -= n;
 | 
				
			||||||
 | 
					                arg++;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        out:
 | 
					            /* Null terminate the string.  */
 | 
				
			||||||
#endif
 | 
					            *s = 0;
 | 
				
			||||||
            /* Unlock the buffer on the ARM side.  */
 | 
					            len = s - cmdline_buffer;
 | 
				
			||||||
            unlock_user(output_buffer, ARG(0), output_size);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return status;
 | 
					            /* Unlock the buffer on the ARM side.  */
 | 
				
			||||||
 | 
					            unlock_user(cmdline_buffer, ARG(0), len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Adjust the commandline length argument.  */
 | 
				
			||||||
 | 
					            SET_ARG(1, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Return success if commandline fit into buffer.  */
 | 
				
			||||||
 | 
					            return *arg ? -1 : 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_HEAPINFO:
 | 
					#else
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    case SYS_HEAPINFO:
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            uint32_t *ptr;
 | 
					            uint32_t *ptr;
 | 
				
			||||||
            uint32_t limit;
 | 
					            uint32_t limit;
 | 
				
			||||||
@@ -462,16 +422,15 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
            /* Some C libraries assume the heap immediately follows .bss, so
 | 
					            /* Some C libraries assume the heap immediately follows .bss, so
 | 
				
			||||||
               allocate it using sbrk.  */
 | 
					               allocate it using sbrk.  */
 | 
				
			||||||
            if (!ts->heap_limit) {
 | 
					            if (!ts->heap_limit) {
 | 
				
			||||||
                abi_ulong ret;
 | 
					                long ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ts->heap_base = do_brk(0);
 | 
					                ts->heap_base = do_brk(0);
 | 
				
			||||||
                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
 | 
					                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
 | 
				
			||||||
                /* Try a big heap, and reduce the size if that fails.  */
 | 
					                /* Try a big heap, and reduce the size if that fails.  */
 | 
				
			||||||
                for (;;) {
 | 
					                for (;;) {
 | 
				
			||||||
                    ret = do_brk(limit);
 | 
					                    ret = do_brk(limit);
 | 
				
			||||||
                    if (ret >= limit) {
 | 
					                    if (ret != -1)
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    limit = (ts->heap_base >> 1) + (limit >> 1);
 | 
					                    limit = (ts->heap_base >> 1) + (limit >> 1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                ts->heap_limit = limit;
 | 
					                ts->heap_limit = limit;
 | 
				
			||||||
@@ -499,8 +458,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case TARGET_SYS_EXIT:
 | 
					    case SYS_EXIT:
 | 
				
			||||||
        gdb_exit(env, 0);
 | 
					 | 
				
			||||||
        exit(0);
 | 
					        exit(0);
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
 | 
					        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
 | 
				
			||||||
							
								
								
									
										12
									
								
								arm.ld
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								arm.ld
									
									
									
									
									
								
							@@ -71,23 +71,23 @@ SECTIONS
 | 
				
			|||||||
  .data1   : { *(.data1) }
 | 
					  .data1   : { *(.data1) }
 | 
				
			||||||
  .preinit_array     :
 | 
					  .preinit_array     :
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    PROVIDE (__preinit_array_start = .);
 | 
					    PROVIDE_HIDDEN (__preinit_array_start = .);
 | 
				
			||||||
    KEEP (*(.preinit_array))
 | 
					    KEEP (*(.preinit_array))
 | 
				
			||||||
    PROVIDE (__preinit_array_end = .);
 | 
					    PROVIDE_HIDDEN (__preinit_array_end = .);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  .init_array     :
 | 
					  .init_array     :
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
     PROVIDE (__init_array_start = .);
 | 
					     PROVIDE_HIDDEN (__init_array_start = .);
 | 
				
			||||||
     KEEP (*(SORT(.init_array.*)))
 | 
					     KEEP (*(SORT(.init_array.*)))
 | 
				
			||||||
     KEEP (*(.init_array))
 | 
					     KEEP (*(.init_array))
 | 
				
			||||||
     PROVIDE (__init_array_end = .);
 | 
					     PROVIDE_HIDDEN (__init_array_end = .);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  .fini_array     :
 | 
					  .fini_array     :
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    PROVIDE (__fini_array_start = .);
 | 
					    PROVIDE_HIDDEN (__fini_array_start = .);
 | 
				
			||||||
    KEEP (*(.fini_array))
 | 
					    KEEP (*(.fini_array))
 | 
				
			||||||
    KEEP (*(SORT(.fini_array.*)))
 | 
					    KEEP (*(SORT(.fini_array.*)))
 | 
				
			||||||
    PROVIDE (__fini_array_end = .);
 | 
					    PROVIDE_HIDDEN (__fini_array_end = .);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  .ctors         :
 | 
					  .ctors         :
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										134
									
								
								async.c
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								async.c
									
									
									
									
									
								
							@@ -24,10 +24,93 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
#include "qemu-aio.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) */
 | 
					/* bottom halves (can be seen as timers which expire ASAP) */
 | 
				
			||||||
@@ -35,34 +118,30 @@ static struct QEMUBH *first_bh;
 | 
				
			|||||||
struct QEMUBH {
 | 
					struct QEMUBH {
 | 
				
			||||||
    QEMUBHFunc *cb;
 | 
					    QEMUBHFunc *cb;
 | 
				
			||||||
    void *opaque;
 | 
					    void *opaque;
 | 
				
			||||||
 | 
					    int scheduled;
 | 
				
			||||||
 | 
					    int idle;
 | 
				
			||||||
 | 
					    int deleted;
 | 
				
			||||||
    QEMUBH *next;
 | 
					    QEMUBH *next;
 | 
				
			||||||
    bool scheduled;
 | 
					 | 
				
			||||||
    bool idle;
 | 
					 | 
				
			||||||
    bool deleted;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
 | 
					QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QEMUBH *bh;
 | 
					    QEMUBH *bh;
 | 
				
			||||||
    bh = g_malloc0(sizeof(QEMUBH));
 | 
					    bh = qemu_mallocz(sizeof(QEMUBH));
 | 
				
			||||||
    bh->cb = cb;
 | 
					    bh->cb = cb;
 | 
				
			||||||
    bh->opaque = opaque;
 | 
					    bh->opaque = opaque;
 | 
				
			||||||
    bh->next = first_bh;
 | 
					    bh->next = async_context->first_bh;
 | 
				
			||||||
    first_bh = bh;
 | 
					    async_context->first_bh = bh;
 | 
				
			||||||
    return bh;
 | 
					    return bh;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qemu_bh_poll(void)
 | 
					int qemu_bh_poll(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QEMUBH *bh, **bhp, *next;
 | 
					    QEMUBH *bh, **bhp;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    static int nesting = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    nesting++;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = 0;
 | 
					    ret = 0;
 | 
				
			||||||
    for (bh = first_bh; bh; bh = next) {
 | 
					    for (bh = async_context->first_bh; bh; bh = bh->next) {
 | 
				
			||||||
        next = bh->next;
 | 
					 | 
				
			||||||
        if (!bh->deleted && bh->scheduled) {
 | 
					        if (!bh->deleted && bh->scheduled) {
 | 
				
			||||||
            bh->scheduled = 0;
 | 
					            bh->scheduled = 0;
 | 
				
			||||||
            if (!bh->idle)
 | 
					            if (!bh->idle)
 | 
				
			||||||
@@ -72,20 +151,15 @@ int qemu_bh_poll(void)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nesting--;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* remove deleted bhs */
 | 
					    /* remove deleted bhs */
 | 
				
			||||||
    if (!nesting) {
 | 
					    bhp = &async_context->first_bh;
 | 
				
			||||||
        bhp = &first_bh;
 | 
					    while (*bhp) {
 | 
				
			||||||
        while (*bhp) {
 | 
					        bh = *bhp;
 | 
				
			||||||
            bh = *bhp;
 | 
					        if (bh->deleted) {
 | 
				
			||||||
            if (bh->deleted) {
 | 
					            *bhp = bh->next;
 | 
				
			||||||
                *bhp = bh->next;
 | 
					            qemu_free(bh);
 | 
				
			||||||
                g_free(bh);
 | 
					        } else
 | 
				
			||||||
            } else {
 | 
					            bhp = &bh->next;
 | 
				
			||||||
                bhp = &bh->next;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
@@ -120,11 +194,11 @@ void qemu_bh_delete(QEMUBH *bh)
 | 
				
			|||||||
    bh->deleted = 1;
 | 
					    bh->deleted = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qemu_bh_update_timeout(uint32_t *timeout)
 | 
					void qemu_bh_update_timeout(int *timeout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QEMUBH *bh;
 | 
					    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->deleted && bh->scheduled) {
 | 
				
			||||||
            if (bh->idle) {
 | 
					            if (bh->idle) {
 | 
				
			||||||
                /* idle bottom halves will be polled at least
 | 
					                /* idle bottom halves will be polled at least
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +0,0 @@
 | 
				
			|||||||
common-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_SDL) += sdlaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_OSS) += ossaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_SPICE) += spiceaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_COREAUDIO) += coreaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_ALSA) += alsaaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_DSOUND) += dsoundaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_FMOD) += fmodaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_ESD) += esdaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_PA) += paaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
 | 
					 | 
				
			||||||
common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
 | 
					 | 
				
			||||||
common-obj-y += wavcapture.o
 | 
					 | 
				
			||||||
@@ -136,7 +136,7 @@ static void alsa_fini_poll (struct pollhlp *hlp)
 | 
				
			|||||||
        for (i = 0; i < hlp->count; ++i) {
 | 
					        for (i = 0; i < hlp->count; ++i) {
 | 
				
			||||||
            qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
 | 
					            qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        g_free (pfds);
 | 
					        qemu_free (pfds);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    hlp->pfds = NULL;
 | 
					    hlp->pfds = NULL;
 | 
				
			||||||
    hlp->count = 0;
 | 
					    hlp->count = 0;
 | 
				
			||||||
@@ -260,7 +260,7 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
 | 
				
			|||||||
    if (err < 0) {
 | 
					    if (err < 0) {
 | 
				
			||||||
        alsa_logerr (err, "Could not initialize poll mode\n"
 | 
					        alsa_logerr (err, "Could not initialize poll mode\n"
 | 
				
			||||||
                     "Could not obtain poll descriptors\n");
 | 
					                     "Could not obtain poll descriptors\n");
 | 
				
			||||||
        g_free (pfds);
 | 
					        qemu_free (pfds);
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -288,7 +288,7 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
 | 
				
			|||||||
            while (i--) {
 | 
					            while (i--) {
 | 
				
			||||||
                qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
 | 
					                qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            g_free (pfds);
 | 
					            qemu_free (pfds);
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -318,7 +318,7 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
 | 
				
			|||||||
    return audio_pcm_sw_write (sw, buf, 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) {
 | 
					    switch (fmt) {
 | 
				
			||||||
    case AUD_FMT_S8:
 | 
					    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;
 | 
					        return SND_PCM_FORMAT_U8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_S16:
 | 
					    case AUD_FMT_S16:
 | 
				
			||||||
        if (endianness) {
 | 
					        return SND_PCM_FORMAT_S16_LE;
 | 
				
			||||||
            return SND_PCM_FORMAT_S16_BE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            return SND_PCM_FORMAT_S16_LE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_U16:
 | 
					    case AUD_FMT_U16:
 | 
				
			||||||
        if (endianness) {
 | 
					        return SND_PCM_FORMAT_U16_LE;
 | 
				
			||||||
            return SND_PCM_FORMAT_U16_BE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            return SND_PCM_FORMAT_U16_LE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_S32:
 | 
					    case AUD_FMT_S32:
 | 
				
			||||||
        if (endianness) {
 | 
					        return SND_PCM_FORMAT_S32_LE;
 | 
				
			||||||
            return SND_PCM_FORMAT_S32_BE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            return SND_PCM_FORMAT_S32_LE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_U32:
 | 
					    case AUD_FMT_U32:
 | 
				
			||||||
        if (endianness) {
 | 
					        return SND_PCM_FORMAT_U32_LE;
 | 
				
			||||||
            return SND_PCM_FORMAT_U32_BE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            return SND_PCM_FORMAT_U32_LE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 | 
					        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,
 | 
					static void alsa_dump_info (struct alsa_params_req *req,
 | 
				
			||||||
                            struct alsa_params_obt *obt,
 | 
					                            struct alsa_params_obt *obt)
 | 
				
			||||||
                            snd_pcm_format_t obtfmt)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    dolog ("parameter | requested value | obtained value\n");
 | 
					    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",
 | 
					    dolog ("channels  |      %10d |     %10d\n",
 | 
				
			||||||
           req->nchannels, obt->nchannels);
 | 
					           req->nchannels, obt->nchannels);
 | 
				
			||||||
    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
 | 
					    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;
 | 
					    *handlep = handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (conf.verbose &&
 | 
					    if (conf.verbose &&
 | 
				
			||||||
        (obtfmt != req->fmt ||
 | 
					        (obt->fmt != req->fmt ||
 | 
				
			||||||
         obt->nchannels != req->nchannels ||
 | 
					         obt->nchannels != req->nchannels ||
 | 
				
			||||||
         obt->freq != req->freq)) {
 | 
					         obt->freq != req->freq)) {
 | 
				
			||||||
        dolog ("Audio parameters for %s\n", typ);
 | 
					        dolog ("Audio parameters for %s\n", typ);
 | 
				
			||||||
        alsa_dump_info (req, obt, obtfmt);
 | 
					        alsa_dump_info (req, obt);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG
 | 
					#ifdef DEBUG
 | 
				
			||||||
    alsa_dump_info (req, obt, obtfmt);
 | 
					    alsa_dump_info (req, obt);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -816,7 +795,7 @@ static void alsa_fini_out (HWVoiceOut *hw)
 | 
				
			|||||||
    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 | 
					    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (alsa->pcm_buf) {
 | 
					    if (alsa->pcm_buf) {
 | 
				
			||||||
        g_free (alsa->pcm_buf);
 | 
					        qemu_free (alsa->pcm_buf);
 | 
				
			||||||
        alsa->pcm_buf = NULL;
 | 
					        alsa->pcm_buf = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -829,7 +808,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
    snd_pcm_t *handle;
 | 
					    snd_pcm_t *handle;
 | 
				
			||||||
    struct audsettings obt_as;
 | 
					    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.freq = as->freq;
 | 
				
			||||||
    req.nchannels = as->nchannels;
 | 
					    req.nchannels = as->nchannels;
 | 
				
			||||||
    req.period_size = conf.period_size_out;
 | 
					    req.period_size = conf.period_size_out;
 | 
				
			||||||
@@ -863,15 +842,11 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VOICE_CTL_PAUSE 0
 | 
					static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
 | 
				
			||||||
#define VOICE_CTL_PREPARE 1
 | 
					 | 
				
			||||||
#define VOICE_CTL_START 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int err;
 | 
					    int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ctl == VOICE_CTL_PAUSE) {
 | 
					    if (pause) {
 | 
				
			||||||
        err = snd_pcm_drop (handle);
 | 
					        err = snd_pcm_drop (handle);
 | 
				
			||||||
        if (err < 0) {
 | 
					        if (err < 0) {
 | 
				
			||||||
            alsa_logerr (err, "Could not stop %s\n", typ);
 | 
					            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);
 | 
					            alsa_logerr (err, "Could not prepare handle for %s\n", typ);
 | 
				
			||||||
            return -1;
 | 
					            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;
 | 
					    return 0;
 | 
				
			||||||
@@ -915,16 +883,12 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
 | 
				
			|||||||
                poll_mode = 0;
 | 
					                poll_mode = 0;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            hw->poll_mode = poll_mode;
 | 
					            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:
 | 
					    case VOICE_DISABLE:
 | 
				
			||||||
        ldebug ("disabling voice\n");
 | 
					        ldebug ("disabling voice\n");
 | 
				
			||||||
        if (hw->poll_mode) {
 | 
					        return alsa_voice_ctl (alsa->handle, "playback", 1);
 | 
				
			||||||
            hw->poll_mode = 0;
 | 
					 | 
				
			||||||
            alsa_fini_poll (&alsa->pollhlp);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
@@ -938,7 +902,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
				
			|||||||
    snd_pcm_t *handle;
 | 
					    snd_pcm_t *handle;
 | 
				
			||||||
    struct audsettings obt_as;
 | 
					    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.freq = as->freq;
 | 
				
			||||||
    req.nchannels = as->nchannels;
 | 
					    req.nchannels = as->nchannels;
 | 
				
			||||||
    req.period_size = conf.period_size_in;
 | 
					    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);
 | 
					    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (alsa->pcm_buf) {
 | 
					    if (alsa->pcm_buf) {
 | 
				
			||||||
        g_free (alsa->pcm_buf);
 | 
					        qemu_free (alsa->pcm_buf);
 | 
				
			||||||
        alsa->pcm_buf = NULL;
 | 
					        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);
 | 
					            src = advance (src, nread << hwshift);
 | 
				
			||||||
            dst += nread;
 | 
					            dst += nread;
 | 
				
			||||||
@@ -1137,7 +1101,7 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            hw->poll_mode = poll_mode;
 | 
					            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:
 | 
					    case VOICE_DISABLE:
 | 
				
			||||||
@@ -1146,7 +1110,7 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 | 
				
			|||||||
            hw->poll_mode = 0;
 | 
					            hw->poll_mode = 0;
 | 
				
			||||||
            alsa_fini_poll (&alsa->pollhlp);
 | 
					            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;
 | 
					    return -1;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										124
									
								
								audio/audio.c
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								audio/audio.c
									
									
									
									
									
								
							@@ -44,9 +44,6 @@
 | 
				
			|||||||
    that we generate the list.
 | 
					    that we generate the list.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
static struct audio_driver *drvtab[] = {
 | 
					static struct audio_driver *drvtab[] = {
 | 
				
			||||||
#ifdef CONFIG_SPICE
 | 
					 | 
				
			||||||
    &spice_audio_driver,
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    CONFIG_AUDIO_DRIVERS
 | 
					    CONFIG_AUDIO_DRIVERS
 | 
				
			||||||
    &no_audio_driver,
 | 
					    &no_audio_driver,
 | 
				
			||||||
    &wav_audio_driver
 | 
					    &wav_audio_driver
 | 
				
			||||||
@@ -104,7 +101,7 @@ static struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static AudioState glob_audio_state;
 | 
					static AudioState glob_audio_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct mixeng_volume nominal_volume = {
 | 
					struct mixeng_volume nominal_volume = {
 | 
				
			||||||
    .mute = 0,
 | 
					    .mute = 0,
 | 
				
			||||||
#ifdef FLOAT_MIXENG
 | 
					#ifdef FLOAT_MIXENG
 | 
				
			||||||
    .r = 1.0,
 | 
					    .r = 1.0,
 | 
				
			||||||
@@ -118,9 +115,6 @@ const struct mixeng_volume nominal_volume = {
 | 
				
			|||||||
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
 | 
					#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
 | 
				
			||||||
#error No its not
 | 
					#error No its not
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static void audio_print_options (const char *prefix,
 | 
					 | 
				
			||||||
                                 struct audio_option *opt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int audio_bug (const char *funcname, int cond)
 | 
					int audio_bug (const char *funcname, int cond)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (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);
 | 
					        AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
 | 
				
			||||||
        if (!shown) {
 | 
					        if (!shown) {
 | 
				
			||||||
            struct audio_driver *d;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            shown = 1;
 | 
					            shown = 1;
 | 
				
			||||||
            AUD_log (NULL, "Save all your work and restart without audio\n");
 | 
					            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, "Please send bug report to av1474@comtv.ru\n");
 | 
				
			||||||
            AUD_log (NULL, "I am sorry\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");
 | 
					        AUD_log (NULL, "Context:\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -196,7 +184,7 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size)
 | 
				
			|||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return g_malloc0 (len);
 | 
					    return qemu_mallocz (len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *audio_alloc_prefix (const char *s)
 | 
					static char *audio_alloc_prefix (const char *s)
 | 
				
			||||||
@@ -210,7 +198,7 @@ static char *audio_alloc_prefix (const char *s)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    len = strlen (s);
 | 
					    len = strlen (s);
 | 
				
			||||||
    r = g_malloc (len + sizeof (qemu_prefix));
 | 
					    r = qemu_malloc (len + sizeof (qemu_prefix));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    u = r + sizeof (qemu_prefix) - 1;
 | 
					    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 (conf.log_to_monitor) {
 | 
				
			||||||
        if (cap) {
 | 
					        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 {
 | 
					    else {
 | 
				
			||||||
        if (cap) {
 | 
					        if (cap) {
 | 
				
			||||||
@@ -425,7 +413,7 @@ static void audio_print_options (const char *prefix,
 | 
				
			|||||||
        printf ("    %s\n", opt->descr);
 | 
					        printf ("    %s\n", opt->descr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (uprefix);
 | 
					    qemu_free (uprefix);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void audio_process_options (const char *prefix,
 | 
					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
 | 
					         * (includes trailing zero) + zero + underscore (on behalf of
 | 
				
			||||||
         * sizeof) */
 | 
					         * sizeof) */
 | 
				
			||||||
        optlen = len + preflen + sizeof (qemu_prefix) + 1;
 | 
					        optlen = len + preflen + sizeof (qemu_prefix) + 1;
 | 
				
			||||||
        optname = g_malloc (optlen);
 | 
					        optname = qemu_malloc (optlen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pstrcpy (optname, optlen, qemu_prefix);
 | 
					        pstrcpy (optname, optlen, qemu_prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -507,7 +495,7 @@ static void audio_process_options (const char *prefix,
 | 
				
			|||||||
            opt->overriddenp = &opt->overridden;
 | 
					            opt->overriddenp = &opt->overridden;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        *opt->overriddenp = !def;
 | 
					        *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) {
 | 
					    switch (as->fmt) {
 | 
				
			||||||
    case AUD_FMT_S8:
 | 
					    case AUD_FMT_S8:
 | 
				
			||||||
        sign = 1;
 | 
					        sign = 1;
 | 
				
			||||||
        /* fall through */
 | 
					 | 
				
			||||||
    case AUD_FMT_U8:
 | 
					    case AUD_FMT_U8:
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_S16:
 | 
					    case AUD_FMT_S16:
 | 
				
			||||||
        sign = 1;
 | 
					        sign = 1;
 | 
				
			||||||
        /* fall through */
 | 
					 | 
				
			||||||
    case AUD_FMT_U16:
 | 
					    case AUD_FMT_U16:
 | 
				
			||||||
        bits = 16;
 | 
					        bits = 16;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_S32:
 | 
					    case AUD_FMT_S32:
 | 
				
			||||||
        sign = 1;
 | 
					        sign = 1;
 | 
				
			||||||
        /* fall through */
 | 
					 | 
				
			||||||
    case AUD_FMT_U32:
 | 
					    case AUD_FMT_U32:
 | 
				
			||||||
        bits = 32;
 | 
					        bits = 32;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
@@ -705,11 +690,13 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Capture
 | 
					 * 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) src;
 | 
				
			||||||
    (void) dst;
 | 
					    (void) dst;
 | 
				
			||||||
    (void) samples;
 | 
					    (void) samples;
 | 
				
			||||||
 | 
					    (void) vol;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static CaptureVoiceOut *audio_pcm_capture_find_specific (
 | 
					static CaptureVoiceOut *audio_pcm_capture_find_specific (
 | 
				
			||||||
@@ -781,7 +768,7 @@ static void audio_detach_capture (HWVoiceOut *hw)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        QLIST_REMOVE (sw, entries);
 | 
					        QLIST_REMOVE (sw, entries);
 | 
				
			||||||
        QLIST_REMOVE (sc, entries);
 | 
					        QLIST_REMOVE (sc, entries);
 | 
				
			||||||
        g_free (sc);
 | 
					        qemu_free (sc);
 | 
				
			||||||
        if (was_active) {
 | 
					        if (was_active) {
 | 
				
			||||||
            /* We have removed soft voice from the capture:
 | 
					            /* We have removed soft voice from the capture:
 | 
				
			||||||
               this might have changed the overall status of the capture
 | 
					               this might have changed the overall status of the capture
 | 
				
			||||||
@@ -818,11 +805,10 @@ static int audio_attach_capture (HWVoiceOut *hw)
 | 
				
			|||||||
        sw->active = hw->enabled;
 | 
					        sw->active = hw->enabled;
 | 
				
			||||||
        sw->conv = noop_conv;
 | 
					        sw->conv = noop_conv;
 | 
				
			||||||
        sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
 | 
					        sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
 | 
				
			||||||
        sw->vol = nominal_volume;
 | 
					 | 
				
			||||||
        sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
 | 
					        sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
 | 
				
			||||||
        if (!sw->rate) {
 | 
					        if (!sw->rate) {
 | 
				
			||||||
            dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
 | 
					            dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
 | 
				
			||||||
            g_free (sw);
 | 
					            qemu_free (sw);
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
 | 
					        QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
 | 
				
			||||||
@@ -958,10 +944,6 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
 | 
				
			|||||||
        total += isamp;
 | 
					        total += isamp;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) {
 | 
					 | 
				
			||||||
        mixeng_volume (sw->buf, ret, &sw->vol);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sw->clip (buf, sw->buf, ret);
 | 
					    sw->clip (buf, sw->buf, ret);
 | 
				
			||||||
    sw->total_hw_samples_acquired += total;
 | 
					    sw->total_hw_samples_acquired += total;
 | 
				
			||||||
    return ret << sw->info.shift;
 | 
					    return ret << sw->info.shift;
 | 
				
			||||||
@@ -1043,11 +1025,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
 | 
				
			|||||||
    swlim = ((int64_t) dead << 32) / sw->ratio;
 | 
					    swlim = ((int64_t) dead << 32) / sw->ratio;
 | 
				
			||||||
    swlim = audio_MIN (swlim, samples);
 | 
					    swlim = audio_MIN (swlim, samples);
 | 
				
			||||||
    if (swlim) {
 | 
					    if (swlim) {
 | 
				
			||||||
        sw->conv (sw->buf, buf, swlim);
 | 
					        sw->conv (sw->buf, buf, swlim, &sw->vol);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) {
 | 
					 | 
				
			||||||
            mixeng_volume (sw->buf, swlim, &sw->vol);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (swlim) {
 | 
					    while (swlim) {
 | 
				
			||||||
@@ -1106,6 +1084,15 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Timer
 | 
					 * 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)
 | 
					static int audio_is_timer_needed (void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    HWVoiceIn *hwi = NULL;
 | 
					    HWVoiceIn *hwi = NULL;
 | 
				
			||||||
@@ -1120,22 +1107,18 @@ static int audio_is_timer_needed (void)
 | 
				
			|||||||
    return 0;
 | 
					    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 ()) {
 | 
					    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 {
 | 
					    else {
 | 
				
			||||||
        qemu_del_timer (s->ts);
 | 
					        qemu_del_timer (s->ts);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void audio_timer (void *opaque)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    audio_run ("timer");
 | 
					 | 
				
			||||||
    audio_reset_timer (opaque);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Public API
 | 
					 * Public API
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -1200,7 +1183,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
 | 
				
			|||||||
                hw->enabled = 1;
 | 
					                hw->enabled = 1;
 | 
				
			||||||
                if (s->vm_running) {
 | 
					                if (s->vm_running) {
 | 
				
			||||||
                    hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
 | 
					                    hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
 | 
				
			||||||
                    audio_reset_timer (s);
 | 
					                    audio_reset_timer ();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1245,7 +1228,6 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
 | 
				
			|||||||
                hw->enabled = 1;
 | 
					                hw->enabled = 1;
 | 
				
			||||||
                if (s->vm_running) {
 | 
					                if (s->vm_running) {
 | 
				
			||||||
                    hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
 | 
					                    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;
 | 
					            sw->total_hw_samples_acquired = hw->total_samples_captured;
 | 
				
			||||||
@@ -1674,7 +1656,7 @@ static void audio_pp_nb_voices (const char *typ, int nb)
 | 
				
			|||||||
        printf ("Theoretically supports many %s voices\n", typ);
 | 
					        printf ("Theoretically supports many %s voices\n", typ);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        printf ("Theoretically supports up to %d %s voices\n", nb, typ);
 | 
					        printf ("Theoretically supports upto %d %s voices\n", nb, typ);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1752,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,
 | 
					static void audio_vm_change_state_handler (void *opaque, int running,
 | 
				
			||||||
                                           RunState state)
 | 
					                                           int reason)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AudioState *s = opaque;
 | 
					    AudioState *s = opaque;
 | 
				
			||||||
    HWVoiceOut *hwo = NULL;
 | 
					    HWVoiceOut *hwo = NULL;
 | 
				
			||||||
@@ -1767,7 +1749,7 @@ static void audio_vm_change_state_handler (void *opaque, int running,
 | 
				
			|||||||
    while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
 | 
					    while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
 | 
				
			||||||
        hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
 | 
					        hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    audio_reset_timer (s);
 | 
					    audio_reset_timer ();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void audio_atexit (void)
 | 
					static void audio_atexit (void)
 | 
				
			||||||
@@ -1776,12 +1758,10 @@ static void audio_atexit (void)
 | 
				
			|||||||
    HWVoiceOut *hwo = NULL;
 | 
					    HWVoiceOut *hwo = NULL;
 | 
				
			||||||
    HWVoiceIn *hwi = NULL;
 | 
					    HWVoiceIn *hwi = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while ((hwo = audio_pcm_hw_find_any_out (hwo))) {
 | 
					    while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
 | 
				
			||||||
        SWVoiceCap *sc;
 | 
					        SWVoiceCap *sc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (hwo->enabled) {
 | 
					        hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
 | 
				
			||||||
            hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        hwo->pcm_ops->fini_out (hwo);
 | 
					        hwo->pcm_ops->fini_out (hwo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
 | 
					        for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
 | 
				
			||||||
@@ -1794,10 +1774,8 @@ static void audio_atexit (void)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while ((hwi = audio_pcm_hw_find_any_in (hwi))) {
 | 
					    while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
 | 
				
			||||||
        if (hwi->enabled) {
 | 
					        hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
 | 
				
			||||||
            hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        hwi->pcm_ops->fini_in (hwi);
 | 
					        hwi->pcm_ops->fini_in (hwi);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1833,7 +1811,7 @@ static void audio_init (void)
 | 
				
			|||||||
    QLIST_INIT (&s->cap_head);
 | 
					    QLIST_INIT (&s->cap_head);
 | 
				
			||||||
    atexit (audio_atexit);
 | 
					    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) {
 | 
					    if (!s->ts) {
 | 
				
			||||||
        hw_error("Could not create audio timer\n");
 | 
					        hw_error("Could not create audio timer\n");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -1914,13 +1892,13 @@ static void audio_init (void)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QLIST_INIT (&s->card_head);
 | 
					    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)
 | 
					void AUD_register_card (const char *name, QEMUSoundCard *card)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    audio_init ();
 | 
					    audio_init ();
 | 
				
			||||||
    card->name = g_strdup (name);
 | 
					    card->name = qemu_strdup (name);
 | 
				
			||||||
    memset (&card->entries, 0, sizeof (card->entries));
 | 
					    memset (&card->entries, 0, sizeof (card->entries));
 | 
				
			||||||
    QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
 | 
					    QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1928,7 +1906,7 @@ void AUD_register_card (const char *name, QEMUSoundCard *card)
 | 
				
			|||||||
void AUD_remove_card (QEMUSoundCard *card)
 | 
					void AUD_remove_card (QEMUSoundCard *card)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QLIST_REMOVE (card, entries);
 | 
					    QLIST_REMOVE (card, entries);
 | 
				
			||||||
    g_free (card->name);
 | 
					    qemu_free (card->name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2013,11 +1991,11 @@ CaptureVoiceOut *AUD_add_capture (
 | 
				
			|||||||
        return cap;
 | 
					        return cap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    err3:
 | 
					    err3:
 | 
				
			||||||
        g_free (cap->hw.mix_buf);
 | 
					        qemu_free (cap->hw.mix_buf);
 | 
				
			||||||
    err2:
 | 
					    err2:
 | 
				
			||||||
        g_free (cap);
 | 
					        qemu_free (cap);
 | 
				
			||||||
    err1:
 | 
					    err1:
 | 
				
			||||||
        g_free (cb);
 | 
					        qemu_free (cb);
 | 
				
			||||||
    err0:
 | 
					    err0:
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -2031,7 +2009,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
 | 
				
			|||||||
        if (cb->opaque == cb_opaque) {
 | 
					        if (cb->opaque == cb_opaque) {
 | 
				
			||||||
            cb->ops.destroy (cb_opaque);
 | 
					            cb->ops.destroy (cb_opaque);
 | 
				
			||||||
            QLIST_REMOVE (cb, entries);
 | 
					            QLIST_REMOVE (cb, entries);
 | 
				
			||||||
            g_free (cb);
 | 
					            qemu_free (cb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!cap->cb_head.lh_first) {
 | 
					            if (!cap->cb_head.lh_first) {
 | 
				
			||||||
                SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
 | 
					                SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
 | 
				
			||||||
@@ -2049,11 +2027,11 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    QLIST_REMOVE (sw, entries);
 | 
					                    QLIST_REMOVE (sw, entries);
 | 
				
			||||||
                    QLIST_REMOVE (sc, entries);
 | 
					                    QLIST_REMOVE (sc, entries);
 | 
				
			||||||
                    g_free (sc);
 | 
					                    qemu_free (sc);
 | 
				
			||||||
                    sw = sw1;
 | 
					                    sw = sw1;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                QLIST_REMOVE (cap, entries);
 | 
					                QLIST_REMOVE (cap, entries);
 | 
				
			||||||
                g_free (cap);
 | 
					                qemu_free (cap);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -2063,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)
 | 
					void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (sw) {
 | 
					    if (sw) {
 | 
				
			||||||
        HWVoiceOut *hw = sw->hw;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        sw->vol.mute = mute;
 | 
					        sw->vol.mute = mute;
 | 
				
			||||||
        sw->vol.l = nominal_volume.l * lvol / 255;
 | 
					        sw->vol.l = nominal_volume.l * lvol / 255;
 | 
				
			||||||
        sw->vol.r = nominal_volume.r * rvol / 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)
 | 
					void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (sw) {
 | 
					    if (sw) {
 | 
				
			||||||
        HWVoiceIn *hw = sw->hw;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        sw->vol.mute = mute;
 | 
					        sw->vol.mute = mute;
 | 
				
			||||||
        sw->vol.l = nominal_volume.l * lvol / 255;
 | 
					        sw->vol.l = nominal_volume.l * lvol / 255;
 | 
				
			||||||
        sw->vol.r = nominal_volume.r * rvol / 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;
 | 
					    uint64_t old_ts;
 | 
				
			||||||
} QEMUAudioTimeStamp;
 | 
					} QEMUAudioTimeStamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
 | 
					void AUD_vlog (const char *cap, const char *fmt, va_list ap);
 | 
				
			||||||
void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 | 
					void AUD_log (const char *cap, const char *fmt, ...)
 | 
				
			||||||
 | 
					#ifdef __GNUC__
 | 
				
			||||||
 | 
					    __attribute__ ((__format__ (__printf__, 2, 3)))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AUD_help (void);
 | 
					void AUD_help (void);
 | 
				
			||||||
void AUD_register_card (const char *name, QEMUSoundCard *card);
 | 
					void AUD_register_card (const char *name, QEMUSoundCard *card);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,7 +82,6 @@ typedef struct HWVoiceOut {
 | 
				
			|||||||
    int samples;
 | 
					    int samples;
 | 
				
			||||||
    QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
 | 
					    QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
 | 
				
			||||||
    QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
 | 
					    QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
 | 
				
			||||||
    int ctl_caps;
 | 
					 | 
				
			||||||
    struct audio_pcm_ops *pcm_ops;
 | 
					    struct audio_pcm_ops *pcm_ops;
 | 
				
			||||||
    QLIST_ENTRY (HWVoiceOut) entries;
 | 
					    QLIST_ENTRY (HWVoiceOut) entries;
 | 
				
			||||||
} HWVoiceOut;
 | 
					} HWVoiceOut;
 | 
				
			||||||
@@ -102,7 +101,6 @@ typedef struct HWVoiceIn {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    int samples;
 | 
					    int samples;
 | 
				
			||||||
    QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
 | 
					    QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
 | 
				
			||||||
    int ctl_caps;
 | 
					 | 
				
			||||||
    struct audio_pcm_ops *pcm_ops;
 | 
					    struct audio_pcm_ops *pcm_ops;
 | 
				
			||||||
    QLIST_ENTRY (HWVoiceIn) entries;
 | 
					    QLIST_ENTRY (HWVoiceIn) entries;
 | 
				
			||||||
} HWVoiceIn;
 | 
					} HWVoiceIn;
 | 
				
			||||||
@@ -152,7 +150,6 @@ struct audio_driver {
 | 
				
			|||||||
    int max_voices_in;
 | 
					    int max_voices_in;
 | 
				
			||||||
    int voice_size_out;
 | 
					    int voice_size_out;
 | 
				
			||||||
    int voice_size_in;
 | 
					    int voice_size_in;
 | 
				
			||||||
    int ctl_caps;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct audio_pcm_ops {
 | 
					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 dsound_audio_driver;
 | 
				
			||||||
extern struct audio_driver esd_audio_driver;
 | 
					extern struct audio_driver esd_audio_driver;
 | 
				
			||||||
extern struct audio_driver pa_audio_driver;
 | 
					extern struct audio_driver pa_audio_driver;
 | 
				
			||||||
extern struct audio_driver spice_audio_driver;
 | 
					 | 
				
			||||||
extern struct audio_driver winwave_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_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);
 | 
					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_ENABLE 1
 | 
				
			||||||
#define VOICE_DISABLE 2
 | 
					#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)
 | 
					static inline int audio_ring_dist (int dst, int src, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return (dst >= src) ? (dst - src) : (len - src + dst);
 | 
					    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, ...)
 | 
					static void GCC_ATTR dolog (const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    va_list ap;
 | 
					    va_list ap;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,8 +6,7 @@
 | 
				
			|||||||
#include "audio_int.h"
 | 
					#include "audio_int.h"
 | 
				
			||||||
#include "audio_pt_int.h"
 | 
					#include "audio_pt_int.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err,
 | 
					static void logerr (struct audio_pt *pt, int err, const char *fmt, ...)
 | 
				
			||||||
                                       const char *fmt, ...)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    va_list ap;
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,16 +23,9 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    int err, err2;
 | 
					    int err, err2;
 | 
				
			||||||
    const char *efunc;
 | 
					    const char *efunc;
 | 
				
			||||||
    sigset_t set, old_set;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p->drv = drv;
 | 
					    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);
 | 
					    err = pthread_mutex_init (&p->mutex, NULL);
 | 
				
			||||||
    if (err) {
 | 
					    if (err) {
 | 
				
			||||||
        efunc = "pthread_mutex_init";
 | 
					        efunc = "pthread_mutex_init";
 | 
				
			||||||
@@ -46,23 +38,7 @@ int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
 | 
				
			|||||||
        goto err1;
 | 
					        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);
 | 
					    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) {
 | 
					    if (err) {
 | 
				
			||||||
        efunc = "pthread_create";
 | 
					        efunc = "pthread_create";
 | 
				
			||||||
        goto err2;
 | 
					        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)
 | 
					static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (HWBUF) {
 | 
					    if (HWBUF) {
 | 
				
			||||||
        g_free (HWBUF);
 | 
					        qemu_free (HWBUF);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HWBUF = NULL;
 | 
					    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)
 | 
					static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (sw->buf) {
 | 
					    if (sw->buf) {
 | 
				
			||||||
        g_free (sw->buf);
 | 
					        qemu_free (sw->buf);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (sw->rate) {
 | 
					    if (sw->rate) {
 | 
				
			||||||
@@ -108,7 +108,11 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    int samples;
 | 
					    int samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DAC
 | 
				
			||||||
 | 
					    samples = sw->hw->samples;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
    samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
 | 
					    samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
 | 
					    sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
 | 
				
			||||||
    if (!sw->buf) {
 | 
					    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);
 | 
					    sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    if (!sw->rate) {
 | 
					    if (!sw->rate) {
 | 
				
			||||||
        g_free (sw->buf);
 | 
					        qemu_free (sw->buf);
 | 
				
			||||||
        sw->buf = NULL;
 | 
					        sw->buf = NULL;
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -160,10 +164,10 @@ static int glue (audio_pcm_sw_init_, TYPE) (
 | 
				
			|||||||
        [sw->info.swap_endianness]
 | 
					        [sw->info.swap_endianness]
 | 
				
			||||||
        [audio_bits_to_index (sw->info.bits)];
 | 
					        [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);
 | 
					    err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
 | 
				
			||||||
    if (err) {
 | 
					    if (err) {
 | 
				
			||||||
        g_free (sw->name);
 | 
					        qemu_free (sw->name);
 | 
				
			||||||
        sw->name = NULL;
 | 
					        sw->name = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return err;
 | 
					    return err;
 | 
				
			||||||
@@ -173,7 +177,7 @@ static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    glue (audio_pcm_sw_free_resources_, TYPE) (sw);
 | 
					    glue (audio_pcm_sw_free_resources_, TYPE) (sw);
 | 
				
			||||||
    if (sw->name) {
 | 
					    if (sw->name) {
 | 
				
			||||||
        g_free (sw->name);
 | 
					        qemu_free (sw->name);
 | 
				
			||||||
        sw->name = NULL;
 | 
					        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 (s->nb_hw_voices_, TYPE) += 1;
 | 
				
			||||||
        glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
 | 
					        glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
 | 
				
			||||||
        glue (hw->pcm_ops->fini_, TYPE) (hw);
 | 
					        glue (hw->pcm_ops->fini_, TYPE) (hw);
 | 
				
			||||||
        g_free (hw);
 | 
					        qemu_free (hw);
 | 
				
			||||||
        *hwp = NULL;
 | 
					        *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->pcm_ops = drv->pcm_ops;
 | 
				
			||||||
    hw->ctl_caps = drv->ctl_caps;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QLIST_INIT (&hw->sw_head);
 | 
					    QLIST_INIT (&hw->sw_head);
 | 
				
			||||||
#ifdef DAC
 | 
					#ifdef DAC
 | 
				
			||||||
    QLIST_INIT (&hw->cap_head);
 | 
					    QLIST_INIT (&hw->cap_head);
 | 
				
			||||||
@@ -302,7 +304,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
 | 
				
			|||||||
 err1:
 | 
					 err1:
 | 
				
			||||||
    glue (hw->pcm_ops->fini_, TYPE) (hw);
 | 
					    glue (hw->pcm_ops->fini_, TYPE) (hw);
 | 
				
			||||||
 err0:
 | 
					 err0:
 | 
				
			||||||
    g_free (hw);
 | 
					    qemu_free (hw);
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -370,7 +372,7 @@ err3:
 | 
				
			|||||||
    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
 | 
					    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
 | 
				
			||||||
    glue (audio_pcm_hw_gc_, TYPE) (&hw);
 | 
					    glue (audio_pcm_hw_gc_, TYPE) (&hw);
 | 
				
			||||||
err2:
 | 
					err2:
 | 
				
			||||||
    g_free (sw);
 | 
					    qemu_free (sw);
 | 
				
			||||||
err1:
 | 
					err1:
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -380,7 +382,7 @@ static void glue (audio_close_, TYPE) (SW *sw)
 | 
				
			|||||||
    glue (audio_pcm_sw_fini_, TYPE) (sw);
 | 
					    glue (audio_pcm_sw_fini_, TYPE) (sw);
 | 
				
			||||||
    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
 | 
					    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
 | 
				
			||||||
    glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
 | 
					    glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
 | 
				
			||||||
    g_free (sw);
 | 
					    qemu_free (sw);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *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;
 | 
					    cur_ts = sw->hw->ts_helper;
 | 
				
			||||||
    old_ts = ts->old_ts;
 | 
					    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) {
 | 
					    if (cur_ts >= old_ts) {
 | 
				
			||||||
        delta = cur_ts - old_ts;
 | 
					        delta = cur_ts - old_ts;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,7 +56,7 @@ typedef struct coreaudioVoiceOut {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void coreaudio_logstatus (OSStatus status)
 | 
					static void coreaudio_logstatus (OSStatus status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const char *str = "BUG";
 | 
					    char *str = "BUG";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch(status) {
 | 
					    switch(status) {
 | 
				
			||||||
    case kAudioHardwareNoError:
 | 
					    case kAudioHardwareNoError:
 | 
				
			||||||
@@ -104,7 +104,7 @@ static void coreaudio_logstatus (OSStatus status)
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
 | 
					        AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -360,8 +360,8 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
        &core->audioDevicePropertyBufferFrameSize);
 | 
					        &core->audioDevicePropertyBufferFrameSize);
 | 
				
			||||||
    if (status != kAudioHardwareNoError) {
 | 
					    if (status != kAudioHardwareNoError) {
 | 
				
			||||||
        coreaudio_logerr2 (status, typ,
 | 
					        coreaudio_logerr2 (status, typ,
 | 
				
			||||||
                           "Could not set device buffer frame size %" PRIu32 "\n",
 | 
					                           "Could not set device buffer frame size %ld\n",
 | 
				
			||||||
                           (uint32_t)core->audioDevicePropertyBufferFrameSize);
 | 
					                           core->audioDevicePropertyBufferFrameSize);
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -831,11 +831,11 @@ static int dsound_run_in (HWVoiceIn *hw)
 | 
				
			|||||||
    decr = len1 + len2;
 | 
					    decr = len1 + len2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (p1 && len1) {
 | 
					    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) {
 | 
					    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);
 | 
					    dsound_unlock_in (dscb, p1, p2, blen1, blen2);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
#include <esd.h>
 | 
					#include <esd.h>
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
#include "audio.h"
 | 
					#include "audio.h"
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AUDIO_CAP "esd"
 | 
					#define AUDIO_CAP "esd"
 | 
				
			||||||
#include "audio_int.h"
 | 
					#include "audio_int.h"
 | 
				
			||||||
@@ -189,6 +190,10 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
 | 
					    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
 | 
				
			||||||
    struct audsettings obt_as = *as;
 | 
					    struct audsettings obt_as = *as;
 | 
				
			||||||
    int esdfmt = ESD_STREAM | ESD_PLAY;
 | 
					    int esdfmt = ESD_STREAM | ESD_PLAY;
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					    sigset_t set, old_set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sigfillset (&set);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
 | 
					    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
 | 
				
			||||||
    switch (as->fmt) {
 | 
					    switch (as->fmt) {
 | 
				
			||||||
@@ -201,7 +206,7 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
    case AUD_FMT_S32:
 | 
					    case AUD_FMT_S32:
 | 
				
			||||||
    case AUD_FMT_U32:
 | 
					    case AUD_FMT_U32:
 | 
				
			||||||
        dolog ("Will use 16 instead of 32 bit samples\n");
 | 
					        dolog ("Will use 16 instead of 32 bit samples\n");
 | 
				
			||||||
        /* fall through */
 | 
					
 | 
				
			||||||
    case AUD_FMT_S16:
 | 
					    case AUD_FMT_S16:
 | 
				
			||||||
    case AUD_FMT_U16:
 | 
					    case AUD_FMT_U16:
 | 
				
			||||||
    deffmt:
 | 
					    deffmt:
 | 
				
			||||||
@@ -226,27 +231,45 @@ static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
 | 
					    esd->fd = -1;
 | 
				
			||||||
    if (esd->fd < 0) {
 | 
					    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
 | 
				
			||||||
        qesd_logerr (errno, "esd_play_stream failed\n");
 | 
					    if (err) {
 | 
				
			||||||
 | 
					        qesd_logerr (err, "pthread_sigmask failed\n");
 | 
				
			||||||
        goto fail1;
 | 
					        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;
 | 
					        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;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail2:
 | 
					 fail3:
 | 
				
			||||||
    if (close (esd->fd)) {
 | 
					    if (close (esd->fd)) {
 | 
				
			||||||
        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
 | 
					        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
 | 
				
			||||||
                     AUDIO_FUNC, esd->fd);
 | 
					                     AUDIO_FUNC, esd->fd);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    esd->fd = -1;
 | 
					    esd->fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 fail2:
 | 
				
			||||||
 | 
					    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
 | 
					        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail1:
 | 
					 fail1:
 | 
				
			||||||
    g_free (esd->pcm_buf);
 | 
					    qemu_free (esd->pcm_buf);
 | 
				
			||||||
    esd->pcm_buf = NULL;
 | 
					    esd->pcm_buf = NULL;
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -270,7 +293,7 @@ static void qesd_fini_out (HWVoiceOut *hw)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    audio_pt_fini (&esd->pt, AUDIO_FUNC);
 | 
					    audio_pt_fini (&esd->pt, AUDIO_FUNC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (esd->pcm_buf);
 | 
					    qemu_free (esd->pcm_buf);
 | 
				
			||||||
    esd->pcm_buf = NULL;
 | 
					    esd->pcm_buf = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -346,7 +369,8 @@ static void *qesd_thread_in (void *arg)
 | 
				
			|||||||
                break;
 | 
					                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;
 | 
					            wpos = (wpos + chunk) % hw->samples;
 | 
				
			||||||
            to_grab -= chunk;
 | 
					            to_grab -= chunk;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -399,6 +423,10 @@ static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
				
			|||||||
    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
 | 
					    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
 | 
				
			||||||
    struct audsettings obt_as = *as;
 | 
					    struct audsettings obt_as = *as;
 | 
				
			||||||
    int esdfmt = ESD_STREAM | ESD_RECORD;
 | 
					    int esdfmt = ESD_STREAM | ESD_RECORD;
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					    sigset_t set, old_set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sigfillset (&set);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
 | 
					    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
 | 
				
			||||||
    switch (as->fmt) {
 | 
					    switch (as->fmt) {
 | 
				
			||||||
@@ -433,27 +461,46 @@ static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
				
			|||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
 | 
					    esd->fd = -1;
 | 
				
			||||||
    if (esd->fd < 0) {
 | 
					
 | 
				
			||||||
        qesd_logerr (errno, "esd_record_stream failed\n");
 | 
					    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
 | 
					        qesd_logerr (err, "pthread_sigmask failed\n");
 | 
				
			||||||
        goto fail1;
 | 
					        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;
 | 
					        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;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail2:
 | 
					 fail3:
 | 
				
			||||||
    if (close (esd->fd)) {
 | 
					    if (close (esd->fd)) {
 | 
				
			||||||
        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
 | 
					        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
 | 
				
			||||||
                     AUDIO_FUNC, esd->fd);
 | 
					                     AUDIO_FUNC, esd->fd);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    esd->fd = -1;
 | 
					    esd->fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 fail2:
 | 
				
			||||||
 | 
					    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
 | 
					        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail1:
 | 
					 fail1:
 | 
				
			||||||
    g_free (esd->pcm_buf);
 | 
					    qemu_free (esd->pcm_buf);
 | 
				
			||||||
    esd->pcm_buf = NULL;
 | 
					    esd->pcm_buf = NULL;
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -477,7 +524,7 @@ static void qesd_fini_in (HWVoiceIn *hw)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    audio_pt_fini (&esd->pt, AUDIO_FUNC);
 | 
					    audio_pt_fini (&esd->pt, AUDIO_FUNC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (esd->pcm_buf);
 | 
					    qemu_free (esd->pcm_buf);
 | 
				
			||||||
    esd->pcm_buf = NULL;
 | 
					    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)
 | 
					static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int mode, channel;
 | 
					    int bits16, mode, channel;
 | 
				
			||||||
    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
 | 
					    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
 | 
				
			||||||
    struct audsettings obt_as = *as;
 | 
					    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? */
 | 
					    /* FMOD always operates on little endian frames? */
 | 
				
			||||||
    obt_as.endianness = 0;
 | 
					    obt_as.endianness = 0;
 | 
				
			||||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
					    audio_pcm_init_info (&hw->info, &obt_as);
 | 
				
			||||||
 | 
					    bits16 = (mode & FSOUND_16BITS) != 0;
 | 
				
			||||||
    hw->samples = conf.nb_samples;
 | 
					    hw->samples = conf.nb_samples;
 | 
				
			||||||
    return 0;
 | 
					    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)
 | 
					static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int mode;
 | 
					    int bits16, mode;
 | 
				
			||||||
    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
 | 
					    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
 | 
				
			||||||
    struct audsettings obt_as = *as;
 | 
					    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? */
 | 
					    /* FMOD always operates on little endian frames? */
 | 
				
			||||||
    obt_as.endianness = 0;
 | 
					    obt_as.endianness = 0;
 | 
				
			||||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
					    audio_pcm_init_info (&hw->info, &obt_as);
 | 
				
			||||||
 | 
					    bits16 = (mode & FSOUND_16BITS) != 0;
 | 
				
			||||||
    hw->samples = conf.nb_samples;
 | 
					    hw->samples = conf.nb_samples;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -486,10 +488,10 @@ static int fmod_run_in (HWVoiceIn *hw)
 | 
				
			|||||||
    decr = len1 + len2;
 | 
					    decr = len1 + len2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (p1 && blen1) {
 | 
					    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) {
 | 
					    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);
 | 
					    fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,8 +33,7 @@
 | 
				
			|||||||
#define ENDIAN_CONVERT(v) (v)
 | 
					#define ENDIAN_CONVERT(v) (v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Signed 8 bit */
 | 
					/* Signed 8 bit */
 | 
				
			||||||
#define BSIZE 8
 | 
					#define IN_T int8_t
 | 
				
			||||||
#define ITYPE int
 | 
					 | 
				
			||||||
#define IN_MIN SCHAR_MIN
 | 
					#define IN_MIN SCHAR_MIN
 | 
				
			||||||
#define IN_MAX SCHAR_MAX
 | 
					#define IN_MAX SCHAR_MAX
 | 
				
			||||||
#define SIGNED
 | 
					#define SIGNED
 | 
				
			||||||
@@ -43,29 +42,25 @@
 | 
				
			|||||||
#undef SIGNED
 | 
					#undef SIGNED
 | 
				
			||||||
#undef IN_MAX
 | 
					#undef IN_MAX
 | 
				
			||||||
#undef IN_MIN
 | 
					#undef IN_MIN
 | 
				
			||||||
#undef BSIZE
 | 
					#undef IN_T
 | 
				
			||||||
#undef ITYPE
 | 
					 | 
				
			||||||
#undef SHIFT
 | 
					#undef SHIFT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Unsigned 8 bit */
 | 
					/* Unsigned 8 bit */
 | 
				
			||||||
#define BSIZE 8
 | 
					#define IN_T uint8_t
 | 
				
			||||||
#define ITYPE uint
 | 
					 | 
				
			||||||
#define IN_MIN 0
 | 
					#define IN_MIN 0
 | 
				
			||||||
#define IN_MAX UCHAR_MAX
 | 
					#define IN_MAX UCHAR_MAX
 | 
				
			||||||
#define SHIFT 8
 | 
					#define SHIFT 8
 | 
				
			||||||
#include "mixeng_template.h"
 | 
					#include "mixeng_template.h"
 | 
				
			||||||
#undef IN_MAX
 | 
					#undef IN_MAX
 | 
				
			||||||
#undef IN_MIN
 | 
					#undef IN_MIN
 | 
				
			||||||
#undef BSIZE
 | 
					#undef IN_T
 | 
				
			||||||
#undef ITYPE
 | 
					 | 
				
			||||||
#undef SHIFT
 | 
					#undef SHIFT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef ENDIAN_CONVERT
 | 
					#undef ENDIAN_CONVERT
 | 
				
			||||||
#undef ENDIAN_CONVERSION
 | 
					#undef ENDIAN_CONVERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Signed 16 bit */
 | 
					/* Signed 16 bit */
 | 
				
			||||||
#define BSIZE 16
 | 
					#define IN_T int16_t
 | 
				
			||||||
#define ITYPE int
 | 
					 | 
				
			||||||
#define IN_MIN SHRT_MIN
 | 
					#define IN_MIN SHRT_MIN
 | 
				
			||||||
#define IN_MAX SHRT_MAX
 | 
					#define IN_MAX SHRT_MAX
 | 
				
			||||||
#define SIGNED
 | 
					#define SIGNED
 | 
				
			||||||
@@ -83,13 +78,11 @@
 | 
				
			|||||||
#undef SIGNED
 | 
					#undef SIGNED
 | 
				
			||||||
#undef IN_MAX
 | 
					#undef IN_MAX
 | 
				
			||||||
#undef IN_MIN
 | 
					#undef IN_MIN
 | 
				
			||||||
#undef BSIZE
 | 
					#undef IN_T
 | 
				
			||||||
#undef ITYPE
 | 
					 | 
				
			||||||
#undef SHIFT
 | 
					#undef SHIFT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Unsigned 16 bit */
 | 
					/* Unsigned 16 bit */
 | 
				
			||||||
#define BSIZE 16
 | 
					#define IN_T uint16_t
 | 
				
			||||||
#define ITYPE uint
 | 
					 | 
				
			||||||
#define IN_MIN 0
 | 
					#define IN_MIN 0
 | 
				
			||||||
#define IN_MAX USHRT_MAX
 | 
					#define IN_MAX USHRT_MAX
 | 
				
			||||||
#define SHIFT 16
 | 
					#define SHIFT 16
 | 
				
			||||||
@@ -105,13 +98,11 @@
 | 
				
			|||||||
#undef ENDIAN_CONVERSION
 | 
					#undef ENDIAN_CONVERSION
 | 
				
			||||||
#undef IN_MAX
 | 
					#undef IN_MAX
 | 
				
			||||||
#undef IN_MIN
 | 
					#undef IN_MIN
 | 
				
			||||||
#undef BSIZE
 | 
					#undef IN_T
 | 
				
			||||||
#undef ITYPE
 | 
					 | 
				
			||||||
#undef SHIFT
 | 
					#undef SHIFT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Signed 32 bit */
 | 
					/* Signed 32 bit */
 | 
				
			||||||
#define BSIZE 32
 | 
					#define IN_T int32_t
 | 
				
			||||||
#define ITYPE int
 | 
					 | 
				
			||||||
#define IN_MIN INT32_MIN
 | 
					#define IN_MIN INT32_MIN
 | 
				
			||||||
#define IN_MAX INT32_MAX
 | 
					#define IN_MAX INT32_MAX
 | 
				
			||||||
#define SIGNED
 | 
					#define SIGNED
 | 
				
			||||||
@@ -129,13 +120,11 @@
 | 
				
			|||||||
#undef SIGNED
 | 
					#undef SIGNED
 | 
				
			||||||
#undef IN_MAX
 | 
					#undef IN_MAX
 | 
				
			||||||
#undef IN_MIN
 | 
					#undef IN_MIN
 | 
				
			||||||
#undef BSIZE
 | 
					#undef IN_T
 | 
				
			||||||
#undef ITYPE
 | 
					 | 
				
			||||||
#undef SHIFT
 | 
					#undef SHIFT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Unsigned 32 bit */
 | 
					/* Unsigned 16 bit */
 | 
				
			||||||
#define BSIZE 32
 | 
					#define IN_T uint32_t
 | 
				
			||||||
#define ITYPE uint
 | 
					 | 
				
			||||||
#define IN_MIN 0
 | 
					#define IN_MIN 0
 | 
				
			||||||
#define IN_MAX UINT32_MAX
 | 
					#define IN_MAX UINT32_MAX
 | 
				
			||||||
#define SHIFT 32
 | 
					#define SHIFT 32
 | 
				
			||||||
@@ -151,8 +140,7 @@
 | 
				
			|||||||
#undef ENDIAN_CONVERSION
 | 
					#undef ENDIAN_CONVERSION
 | 
				
			||||||
#undef IN_MAX
 | 
					#undef IN_MAX
 | 
				
			||||||
#undef IN_MIN
 | 
					#undef IN_MIN
 | 
				
			||||||
#undef BSIZE
 | 
					#undef IN_T
 | 
				
			||||||
#undef ITYPE
 | 
					 | 
				
			||||||
#undef SHIFT
 | 
					#undef SHIFT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
t_sample *mixeng_conv[2][2][2][3] = {
 | 
					t_sample *mixeng_conv[2][2][2][3] = {
 | 
				
			||||||
@@ -338,35 +326,10 @@ void *st_rate_start (int inrate, int outrate)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void st_rate_stop (void *opaque)
 | 
					void st_rate_stop (void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    g_free (opaque);
 | 
					    qemu_free (opaque);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mixeng_clear (struct st_sample *buf, int len)
 | 
					void mixeng_clear (struct st_sample *buf, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    memset (buf, 0, len * sizeof (struct st_sample));
 | 
					    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; };
 | 
					struct st_sample { int64_t l; int64_t r; };
 | 
				
			||||||
#endif
 | 
					#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);
 | 
					typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern t_sample *mixeng_conv[2][2][2][3];
 | 
					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);
 | 
					                       int *isamp, int *osamp);
 | 
				
			||||||
void st_rate_stop (void *opaque);
 | 
					void st_rate_stop (void *opaque);
 | 
				
			||||||
void mixeng_clear (struct st_sample *buf, int len);
 | 
					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 */
 | 
					#endif  /* mixeng.h */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,8 +31,17 @@
 | 
				
			|||||||
#define HALF (IN_MAX >> 1)
 | 
					#define HALF (IN_MAX >> 1)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ET glue (ENDIAN_CONVERSION, glue (glue (glue (_, ITYPE), BSIZE), _t))
 | 
					#ifdef CONFIG_MIXEMU
 | 
				
			||||||
#define IN_T glue (glue (ITYPE, BSIZE), _t)
 | 
					#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
 | 
					#ifdef FLOAT_MIXENG
 | 
				
			||||||
static mixeng_real inline glue (conv_, ET) (IN_T v)
 | 
					static mixeng_real inline glue (conv_, ET) (IN_T v)
 | 
				
			||||||
@@ -47,7 +56,7 @@ static mixeng_real inline glue (conv_, ET) (IN_T v)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#else  /* !RECIPROCAL */
 | 
					#else  /* !RECIPROCAL */
 | 
				
			||||||
#ifdef SIGNED
 | 
					#ifdef SIGNED
 | 
				
			||||||
    return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN);
 | 
					    return nv / (mixeng_real) (IN_MAX - IN_MIN);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    return (nv - HALF) / (mixeng_real) IN_MAX;
 | 
					    return (nv - HALF) / (mixeng_real) IN_MAX;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -64,7 +73,7 @@ static IN_T inline glue (clip_, ET) (mixeng_real v)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SIGNED
 | 
					#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
 | 
					#else
 | 
				
			||||||
    return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
 | 
					    return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -100,26 +109,40 @@ static inline IN_T glue (clip_, ET) (int64_t v)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void glue (glue (conv_, ET), _to_stereo)
 | 
					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;
 | 
					    struct st_sample *out = dst;
 | 
				
			||||||
    IN_T *in = (IN_T *) src;
 | 
					    IN_T *in = (IN_T *) src;
 | 
				
			||||||
 | 
					#ifdef CONFIG_MIXEMU
 | 
				
			||||||
 | 
					    if (vol->mute) {
 | 
				
			||||||
 | 
					        mixeng_clear (dst, samples);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    (void) vol;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    while (samples--) {
 | 
					    while (samples--) {
 | 
				
			||||||
        out->l = glue (conv_, ET) (*in++);
 | 
					        out->l = VOL (glue (conv_, ET) (*in++), vol->l);
 | 
				
			||||||
        out->r = glue (conv_, ET) (*in++);
 | 
					        out->r = VOL (glue (conv_, ET) (*in++), vol->r);
 | 
				
			||||||
        out += 1;
 | 
					        out += 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void glue (glue (conv_, ET), _to_mono)
 | 
					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;
 | 
					    struct st_sample *out = dst;
 | 
				
			||||||
    IN_T *in = (IN_T *) src;
 | 
					    IN_T *in = (IN_T *) src;
 | 
				
			||||||
 | 
					#ifdef CONFIG_MIXEMU
 | 
				
			||||||
 | 
					    if (vol->mute) {
 | 
				
			||||||
 | 
					        mixeng_clear (dst, samples);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    (void) vol;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    while (samples--) {
 | 
					    while (samples--) {
 | 
				
			||||||
        out->l = glue (conv_, ET) (in[0]);
 | 
					        out->l = VOL (glue (conv_, ET) (in[0]), vol->l);
 | 
				
			||||||
        out->r = out->l;
 | 
					        out->r = out->l;
 | 
				
			||||||
        out += 1;
 | 
					        out += 1;
 | 
				
			||||||
        in += 1;
 | 
					        in += 1;
 | 
				
			||||||
@@ -151,4 +174,4 @@ static void glue (glue (clip_, ET), _from_mono)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#undef ET
 | 
					#undef ET
 | 
				
			||||||
#undef HALF
 | 
					#undef HALF
 | 
				
			||||||
#undef IN_T
 | 
					#undef VOL
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ static int no_run_out (HWVoiceOut *hw, int live)
 | 
				
			|||||||
    int64_t ticks;
 | 
					    int64_t ticks;
 | 
				
			||||||
    int64_t bytes;
 | 
					    int64_t bytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    now = qemu_get_clock_ns (vm_clock);
 | 
					    now = qemu_get_clock (vm_clock);
 | 
				
			||||||
    ticks = now - no->old_ticks;
 | 
					    ticks = now - no->old_ticks;
 | 
				
			||||||
    bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
 | 
					    bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
 | 
				
			||||||
    bytes = audio_MIN (bytes, INT_MAX);
 | 
					    bytes = audio_MIN (bytes, INT_MAX);
 | 
				
			||||||
@@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw)
 | 
				
			|||||||
    int samples = 0;
 | 
					    int samples = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dead) {
 | 
					    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 ticks = now - no->old_ticks;
 | 
				
			||||||
        int64_t bytes =
 | 
					        int64_t bytes =
 | 
				
			||||||
            muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
 | 
					            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)
 | 
					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 samples = size >> sw->info.shift;
 | 
				
			||||||
    int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
 | 
					    int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
 | 
				
			||||||
    int to_clear = audio_MIN (samples, total);
 | 
					    int to_clear = audio_MIN (samples, total);
 | 
				
			||||||
    sw->total_hw_samples_acquired += total;
 | 
					 | 
				
			||||||
    audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
 | 
					    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, ...)
 | 
					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);
 | 
					    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) {
 | 
					    switch (fmt) {
 | 
				
			||||||
    case AUD_FMT_S8:
 | 
					    case AUD_FMT_S8:
 | 
				
			||||||
@@ -171,20 +171,10 @@ static int aud_to_ossfmt (audfmt_e fmt, int endianness)
 | 
				
			|||||||
        return AFMT_U8;
 | 
					        return AFMT_U8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_S16:
 | 
					    case AUD_FMT_S16:
 | 
				
			||||||
        if (endianness) {
 | 
					        return AFMT_S16_LE;
 | 
				
			||||||
            return AFMT_S16_BE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            return AFMT_S16_LE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_U16:
 | 
					    case AUD_FMT_U16:
 | 
				
			||||||
        if (endianness) {
 | 
					        return AFMT_U16_LE;
 | 
				
			||||||
            return AFMT_U16_BE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            return AFMT_U16_LE;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 | 
					        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 | 
				
			||||||
@@ -508,7 +498,7 @@ static void oss_fini_out (HWVoiceOut *hw)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            g_free (oss->pcm_buf);
 | 
					            qemu_free (oss->pcm_buf);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        oss->pcm_buf = NULL;
 | 
					        oss->pcm_buf = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -526,7 +516,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    oss->fd = -1;
 | 
					    oss->fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 | 
					    req.fmt = aud_to_ossfmt (as->fmt);
 | 
				
			||||||
    req.freq = as->freq;
 | 
					    req.freq = as->freq;
 | 
				
			||||||
    req.nchannels = as->nchannels;
 | 
					    req.nchannels = as->nchannels;
 | 
				
			||||||
    req.fragsize = conf.fragsize;
 | 
					    req.fragsize = conf.fragsize;
 | 
				
			||||||
@@ -692,7 +682,7 @@ static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    oss->fd = -1;
 | 
					    oss->fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 | 
					    req.fmt = aud_to_ossfmt (as->fmt);
 | 
				
			||||||
    req.freq = as->freq;
 | 
					    req.freq = as->freq;
 | 
				
			||||||
    req.nchannels = as->nchannels;
 | 
					    req.nchannels = as->nchannels;
 | 
				
			||||||
    req.fragsize = conf.fragsize;
 | 
					    req.fragsize = conf.fragsize;
 | 
				
			||||||
@@ -741,7 +731,7 @@ static void oss_fini_in (HWVoiceIn *hw)
 | 
				
			|||||||
    oss_anal_close (&oss->fd);
 | 
					    oss_anal_close (&oss->fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (oss->pcm_buf) {
 | 
					    if (oss->pcm_buf) {
 | 
				
			||||||
        g_free (oss->pcm_buf);
 | 
					        qemu_free (oss->pcm_buf);
 | 
				
			||||||
        oss->pcm_buf = NULL;
 | 
					        oss->pcm_buf = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -788,7 +778,8 @@ static int oss_run_in (HWVoiceIn *hw)
 | 
				
			|||||||
                           hw->info.align + 1);
 | 
					                           hw->info.align + 1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                read_samples += nread >> hwshift;
 | 
					                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) {
 | 
					            if (bufs[i].len - nread) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										551
									
								
								audio/paaudio.c
									
									
									
									
									
								
							
							
						
						
									
										551
									
								
								audio/paaudio.c
									
									
									
									
									
								
							@@ -2,7 +2,8 @@
 | 
				
			|||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
#include "audio.h"
 | 
					#include "audio.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pulse/pulseaudio.h>
 | 
					#include <pulse/simple.h>
 | 
				
			||||||
 | 
					#include <pulse/error.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AUDIO_CAP "pulseaudio"
 | 
					#define AUDIO_CAP "pulseaudio"
 | 
				
			||||||
#include "audio_int.h"
 | 
					#include "audio_int.h"
 | 
				
			||||||
@@ -14,7 +15,7 @@ typedef struct {
 | 
				
			|||||||
    int live;
 | 
					    int live;
 | 
				
			||||||
    int decr;
 | 
					    int decr;
 | 
				
			||||||
    int rpos;
 | 
					    int rpos;
 | 
				
			||||||
    pa_stream *stream;
 | 
					    pa_simple *s;
 | 
				
			||||||
    void *pcm_buf;
 | 
					    void *pcm_buf;
 | 
				
			||||||
    struct audio_pt pt;
 | 
					    struct audio_pt pt;
 | 
				
			||||||
} PAVoiceOut;
 | 
					} PAVoiceOut;
 | 
				
			||||||
@@ -25,24 +26,20 @@ typedef struct {
 | 
				
			|||||||
    int dead;
 | 
					    int dead;
 | 
				
			||||||
    int incr;
 | 
					    int incr;
 | 
				
			||||||
    int wpos;
 | 
					    int wpos;
 | 
				
			||||||
    pa_stream *stream;
 | 
					    pa_simple *s;
 | 
				
			||||||
    void *pcm_buf;
 | 
					    void *pcm_buf;
 | 
				
			||||||
    struct audio_pt pt;
 | 
					    struct audio_pt pt;
 | 
				
			||||||
    const void *read_data;
 | 
					 | 
				
			||||||
    size_t read_index, read_length;
 | 
					 | 
				
			||||||
} PAVoiceIn;
 | 
					} PAVoiceIn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					static struct {
 | 
				
			||||||
    int samples;
 | 
					    int samples;
 | 
				
			||||||
 | 
					    int divisor;
 | 
				
			||||||
    char *server;
 | 
					    char *server;
 | 
				
			||||||
    char *sink;
 | 
					    char *sink;
 | 
				
			||||||
    char *source;
 | 
					    char *source;
 | 
				
			||||||
    pa_threaded_mainloop *mainloop;
 | 
					} conf = {
 | 
				
			||||||
    pa_context *context;
 | 
					    .samples = 1024,
 | 
				
			||||||
} paaudio;
 | 
					    .divisor = 2,
 | 
				
			||||||
 | 
					 | 
				
			||||||
static paaudio glob_paaudio = {
 | 
					 | 
				
			||||||
    .samples = 4096,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
 | 
					static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
 | 
				
			||||||
@@ -56,150 +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));
 | 
					    AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef PA_CONTEXT_IS_GOOD
 | 
					 | 
				
			||||||
static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return
 | 
					 | 
				
			||||||
        x == PA_CONTEXT_CONNECTING ||
 | 
					 | 
				
			||||||
        x == PA_CONTEXT_AUTHORIZING ||
 | 
					 | 
				
			||||||
        x == PA_CONTEXT_SETTING_NAME ||
 | 
					 | 
				
			||||||
        x == PA_CONTEXT_READY;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef PA_STREAM_IS_GOOD
 | 
					 | 
				
			||||||
static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return
 | 
					 | 
				
			||||||
        x == PA_STREAM_CREATING ||
 | 
					 | 
				
			||||||
        x == PA_STREAM_READY;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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)
 | 
					static void *qpa_thread_out (void *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PAVoiceOut *pa = arg;
 | 
					    PAVoiceOut *pa = arg;
 | 
				
			||||||
    HWVoiceOut *hw = &pa->hw;
 | 
					    HWVoiceOut *hw = &pa->hw;
 | 
				
			||||||
 | 
					    int threshold;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 | 
					    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
@@ -213,7 +73,7 @@ static void *qpa_thread_out (void *arg)
 | 
				
			|||||||
                goto exit;
 | 
					                goto exit;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (pa->live > 0) {
 | 
					            if (pa->live > threshold) {
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -222,8 +82,8 @@ static void *qpa_thread_out (void *arg)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2);
 | 
					        decr = to_mix = pa->live;
 | 
				
			||||||
        rpos = pa->rpos;
 | 
					        rpos = hw->rpos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
 | 
					        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
 | 
				
			||||||
            return NULL;
 | 
					            return NULL;
 | 
				
			||||||
@@ -236,8 +96,8 @@ static void *qpa_thread_out (void *arg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            hw->clip (pa->pcm_buf, src, chunk);
 | 
					            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) {
 | 
					                                 chunk << hw->info.shift, &error) < 0) {
 | 
				
			||||||
                qpa_logerr (error, "pa_simple_write failed\n");
 | 
					                qpa_logerr (error, "pa_simple_write failed\n");
 | 
				
			||||||
                return NULL;
 | 
					                return NULL;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -292,6 +152,9 @@ static void *qpa_thread_in (void *arg)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    PAVoiceIn *pa = arg;
 | 
					    PAVoiceIn *pa = arg;
 | 
				
			||||||
    HWVoiceIn *hw = &pa->hw;
 | 
					    HWVoiceIn *hw = &pa->hw;
 | 
				
			||||||
 | 
					    int threshold;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 | 
					    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
@@ -305,7 +168,7 @@ static void *qpa_thread_in (void *arg)
 | 
				
			|||||||
                goto exit;
 | 
					                goto exit;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (pa->dead > 0) {
 | 
					            if (pa->dead > threshold) {
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -314,8 +177,8 @@ static void *qpa_thread_in (void *arg)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2);
 | 
					        incr = to_grab = pa->dead;
 | 
				
			||||||
        wpos = pa->wpos;
 | 
					        wpos = hw->wpos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
 | 
					        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
 | 
				
			||||||
            return NULL;
 | 
					            return NULL;
 | 
				
			||||||
@@ -326,13 +189,13 @@ static void *qpa_thread_in (void *arg)
 | 
				
			|||||||
            int chunk = audio_MIN (to_grab, hw->samples - wpos);
 | 
					            int chunk = audio_MIN (to_grab, hw->samples - wpos);
 | 
				
			||||||
            void *buf = advance (pa->pcm_buf, 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) {
 | 
					                                chunk << hw->info.shift, &error) < 0) {
 | 
				
			||||||
                qpa_logerr (error, "pa_simple_read failed\n");
 | 
					                qpa_logerr (error, "pa_simple_read failed\n");
 | 
				
			||||||
                return NULL;
 | 
					                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;
 | 
					            wpos = (wpos + chunk) % hw->samples;
 | 
				
			||||||
            to_grab -= chunk;
 | 
					            to_grab -= chunk;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -428,117 +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
 | 
					 | 
				
			||||||
#ifdef PA_STREAM_ADJUST_LATENCY
 | 
					 | 
				
			||||||
                                        |PA_STREAM_ADJUST_LATENCY
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                                        |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        r = pa_stream_connect_record (stream, dev, attr,
 | 
					 | 
				
			||||||
                                      PA_STREAM_INTERPOLATE_TIMING
 | 
					 | 
				
			||||||
#ifdef PA_STREAM_ADJUST_LATENCY
 | 
					 | 
				
			||||||
                                      |PA_STREAM_ADJUST_LATENCY
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                                      |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)
 | 
					static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int error;
 | 
					    int error;
 | 
				
			||||||
    static pa_sample_spec ss;
 | 
					    static pa_sample_spec ss;
 | 
				
			||||||
    static pa_buffer_attr ba;
 | 
					 | 
				
			||||||
    struct audsettings obt_as = *as;
 | 
					    struct audsettings obt_as = *as;
 | 
				
			||||||
    PAVoiceOut *pa = (PAVoiceOut *) hw;
 | 
					    PAVoiceOut *pa = (PAVoiceOut *) hw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -546,37 +302,27 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
    ss.channels = as->nchannels;
 | 
					    ss.channels = as->nchannels;
 | 
				
			||||||
    ss.rate = as->freq;
 | 
					    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);
 | 
					    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa->stream = qpa_simple_new (
 | 
					    pa->s = pa_simple_new (
 | 
				
			||||||
        glob_paaudio.server,
 | 
					        conf.server,
 | 
				
			||||||
        "qemu",
 | 
					        "qemu",
 | 
				
			||||||
        PA_STREAM_PLAYBACK,
 | 
					        PA_STREAM_PLAYBACK,
 | 
				
			||||||
        glob_paaudio.sink,
 | 
					        conf.sink,
 | 
				
			||||||
        "pcm.playback",
 | 
					        "pcm.playback",
 | 
				
			||||||
        &ss,
 | 
					        &ss,
 | 
				
			||||||
        NULL,                   /* channel map */
 | 
					        NULL,                   /* channel map */
 | 
				
			||||||
        &ba,                    /* buffering attributes */
 | 
					        NULL,                   /* buffering attributes */
 | 
				
			||||||
        &error
 | 
					        &error
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    if (!pa->stream) {
 | 
					    if (!pa->s) {
 | 
				
			||||||
        qpa_logerr (error, "pa_simple_new for playback failed\n");
 | 
					        qpa_logerr (error, "pa_simple_new for playback failed\n");
 | 
				
			||||||
        goto fail1;
 | 
					        goto fail1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
					    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->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 | 
				
			||||||
    pa->rpos = hw->rpos;
 | 
					 | 
				
			||||||
    if (!pa->pcm_buf) {
 | 
					    if (!pa->pcm_buf) {
 | 
				
			||||||
        dolog ("Could not allocate buffer (%d bytes)\n",
 | 
					        dolog ("Could not allocate buffer (%d bytes)\n",
 | 
				
			||||||
               hw->samples << hw->info.shift);
 | 
					               hw->samples << hw->info.shift);
 | 
				
			||||||
@@ -590,13 +336,11 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail3:
 | 
					 fail3:
 | 
				
			||||||
    g_free (pa->pcm_buf);
 | 
					    qemu_free (pa->pcm_buf);
 | 
				
			||||||
    pa->pcm_buf = NULL;
 | 
					    pa->pcm_buf = NULL;
 | 
				
			||||||
 fail2:
 | 
					 fail2:
 | 
				
			||||||
    if (pa->stream) {
 | 
					    pa_simple_free (pa->s);
 | 
				
			||||||
        pa_stream_unref (pa->stream);
 | 
					    pa->s = NULL;
 | 
				
			||||||
        pa->stream = NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 fail1:
 | 
					 fail1:
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -614,26 +358,25 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 | 
					    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa->stream = qpa_simple_new (
 | 
					    pa->s = pa_simple_new (
 | 
				
			||||||
        glob_paaudio.server,
 | 
					        conf.server,
 | 
				
			||||||
        "qemu",
 | 
					        "qemu",
 | 
				
			||||||
        PA_STREAM_RECORD,
 | 
					        PA_STREAM_RECORD,
 | 
				
			||||||
        glob_paaudio.source,
 | 
					        conf.source,
 | 
				
			||||||
        "pcm.capture",
 | 
					        "pcm.capture",
 | 
				
			||||||
        &ss,
 | 
					        &ss,
 | 
				
			||||||
        NULL,                   /* channel map */
 | 
					        NULL,                   /* channel map */
 | 
				
			||||||
        NULL,                   /* buffering attributes */
 | 
					        NULL,                   /* buffering attributes */
 | 
				
			||||||
        &error
 | 
					        &error
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    if (!pa->stream) {
 | 
					    if (!pa->s) {
 | 
				
			||||||
        qpa_logerr (error, "pa_simple_new for capture failed\n");
 | 
					        qpa_logerr (error, "pa_simple_new for capture failed\n");
 | 
				
			||||||
        goto fail1;
 | 
					        goto fail1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
					    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->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 | 
				
			||||||
    pa->wpos = hw->wpos;
 | 
					 | 
				
			||||||
    if (!pa->pcm_buf) {
 | 
					    if (!pa->pcm_buf) {
 | 
				
			||||||
        dolog ("Could not allocate buffer (%d bytes)\n",
 | 
					        dolog ("Could not allocate buffer (%d bytes)\n",
 | 
				
			||||||
               hw->samples << hw->info.shift);
 | 
					               hw->samples << hw->info.shift);
 | 
				
			||||||
@@ -647,13 +390,11 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail3:
 | 
					 fail3:
 | 
				
			||||||
    g_free (pa->pcm_buf);
 | 
					    qemu_free (pa->pcm_buf);
 | 
				
			||||||
    pa->pcm_buf = NULL;
 | 
					    pa->pcm_buf = NULL;
 | 
				
			||||||
 fail2:
 | 
					 fail2:
 | 
				
			||||||
    if (pa->stream) {
 | 
					    pa_simple_free (pa->s);
 | 
				
			||||||
        pa_stream_unref (pa->stream);
 | 
					    pa->s = NULL;
 | 
				
			||||||
        pa->stream = NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 fail1:
 | 
					 fail1:
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -668,13 +409,13 @@ static void qpa_fini_out (HWVoiceOut *hw)
 | 
				
			|||||||
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 | 
					    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 | 
				
			||||||
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 | 
					    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pa->stream) {
 | 
					    if (pa->s) {
 | 
				
			||||||
        pa_stream_unref (pa->stream);
 | 
					        pa_simple_free (pa->s);
 | 
				
			||||||
        pa->stream = NULL;
 | 
					        pa->s = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
 | 
					    audio_pt_fini (&pa->pt, AUDIO_FUNC);
 | 
				
			||||||
    g_free (pa->pcm_buf);
 | 
					    qemu_free (pa->pcm_buf);
 | 
				
			||||||
    pa->pcm_buf = NULL;
 | 
					    pa->pcm_buf = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -688,225 +429,70 @@ static void qpa_fini_in (HWVoiceIn *hw)
 | 
				
			|||||||
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 | 
					    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 | 
				
			||||||
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 | 
					    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pa->stream) {
 | 
					    if (pa->s) {
 | 
				
			||||||
        pa_stream_unref (pa->stream);
 | 
					        pa_simple_free (pa->s);
 | 
				
			||||||
        pa->stream = NULL;
 | 
					        pa->s = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
 | 
					    audio_pt_fini (&pa->pt, AUDIO_FUNC);
 | 
				
			||||||
    g_free (pa->pcm_buf);
 | 
					    qemu_free (pa->pcm_buf);
 | 
				
			||||||
    pa->pcm_buf = NULL;
 | 
					    pa->pcm_buf = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
 | 
					static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PAVoiceOut *pa = (PAVoiceOut *) hw;
 | 
					    (void) hw;
 | 
				
			||||||
    pa_operation *op;
 | 
					    (void) cmd;
 | 
				
			||||||
    pa_cvolume v;
 | 
					 | 
				
			||||||
    paaudio *g = &glob_paaudio;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef PA_CHECK_VERSION    /* macro is present in 0.9.16+ */
 | 
					 | 
				
			||||||
    pa_cvolume_init (&v);  /* function is present in 0.9.13+ */
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 | 
					static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PAVoiceIn *pa = (PAVoiceIn *) hw;
 | 
					    (void) hw;
 | 
				
			||||||
    pa_operation *op;
 | 
					    (void) cmd;
 | 
				
			||||||
    pa_cvolume v;
 | 
					 | 
				
			||||||
    paaudio *g = &glob_paaudio;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef PA_CHECK_VERSION
 | 
					 | 
				
			||||||
    pa_cvolume_init (&v);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* common */
 | 
					/* common */
 | 
				
			||||||
static void *qpa_audio_init (void)
 | 
					static void *qpa_audio_init (void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    paaudio *g = &glob_paaudio;
 | 
					    return &conf;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void qpa_audio_fini (void *opaque)
 | 
					static void qpa_audio_fini (void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    paaudio *g = opaque;
 | 
					    (void) 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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct audio_option qpa_options[] = {
 | 
					struct audio_option qpa_options[] = {
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        .name  = "SAMPLES",
 | 
					        .name  = "SAMPLES",
 | 
				
			||||||
        .tag   = AUD_OPT_INT,
 | 
					        .tag   = AUD_OPT_INT,
 | 
				
			||||||
        .valp  = &glob_paaudio.samples,
 | 
					        .valp  = &conf.samples,
 | 
				
			||||||
        .descr = "buffer size in samples"
 | 
					        .descr = "buffer size in samples"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .name  = "DIVISOR",
 | 
				
			||||||
 | 
					        .tag   = AUD_OPT_INT,
 | 
				
			||||||
 | 
					        .valp  = &conf.divisor,
 | 
				
			||||||
 | 
					        .descr = "threshold divisor"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        .name  = "SERVER",
 | 
					        .name  = "SERVER",
 | 
				
			||||||
        .tag   = AUD_OPT_STR,
 | 
					        .tag   = AUD_OPT_STR,
 | 
				
			||||||
        .valp  = &glob_paaudio.server,
 | 
					        .valp  = &conf.server,
 | 
				
			||||||
        .descr = "server address"
 | 
					        .descr = "server address"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        .name  = "SINK",
 | 
					        .name  = "SINK",
 | 
				
			||||||
        .tag   = AUD_OPT_STR,
 | 
					        .tag   = AUD_OPT_STR,
 | 
				
			||||||
        .valp  = &glob_paaudio.sink,
 | 
					        .valp  = &conf.sink,
 | 
				
			||||||
        .descr = "sink device name"
 | 
					        .descr = "sink device name"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        .name  = "SOURCE",
 | 
					        .name  = "SOURCE",
 | 
				
			||||||
        .tag   = AUD_OPT_STR,
 | 
					        .tag   = AUD_OPT_STR,
 | 
				
			||||||
        .valp  = &glob_paaudio.source,
 | 
					        .valp  = &conf.source,
 | 
				
			||||||
        .descr = "source device name"
 | 
					        .descr = "source device name"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    { /* End of list */ }
 | 
					    { /* End of list */ }
 | 
				
			||||||
@@ -937,6 +523,5 @@ struct audio_driver pa_audio_driver = {
 | 
				
			|||||||
    .max_voices_out = INT_MAX,
 | 
					    .max_voices_out = INT_MAX,
 | 
				
			||||||
    .max_voices_in  = INT_MAX,
 | 
					    .max_voices_in  = INT_MAX,
 | 
				
			||||||
    .voice_size_out = sizeof (PAVoiceOut),
 | 
					    .voice_size_out = sizeof (PAVoiceOut),
 | 
				
			||||||
    .voice_size_in  = sizeof (PAVoiceIn),
 | 
					    .voice_size_in  = sizeof (PAVoiceIn)
 | 
				
			||||||
    .ctl_caps       = VOICE_VOLUME_CAP
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										136
									
								
								audio/sdlaudio.c
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								audio/sdlaudio.c
									
									
									
									
									
								
							@@ -32,6 +32,7 @@
 | 
				
			|||||||
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
 | 
					#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
 | 
				
			||||||
#include <pthread.h>
 | 
					#include <pthread.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AUDIO_CAP "sdl"
 | 
					#define AUDIO_CAP "sdl"
 | 
				
			||||||
@@ -40,8 +41,8 @@
 | 
				
			|||||||
typedef struct SDLVoiceOut {
 | 
					typedef struct SDLVoiceOut {
 | 
				
			||||||
    HWVoiceOut hw;
 | 
					    HWVoiceOut hw;
 | 
				
			||||||
    int live;
 | 
					    int live;
 | 
				
			||||||
    int rpos;
 | 
					 | 
				
			||||||
    int decr;
 | 
					    int decr;
 | 
				
			||||||
 | 
					    int pending;
 | 
				
			||||||
} SDLVoiceOut;
 | 
					} SDLVoiceOut;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct {
 | 
					static struct {
 | 
				
			||||||
@@ -114,19 +115,23 @@ static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
 | 
				
			|||||||
    return sdl_post (s, 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) {
 | 
					    switch (fmt) {
 | 
				
			||||||
    case AUD_FMT_S8:
 | 
					    case AUD_FMT_S8:
 | 
				
			||||||
 | 
					        *shift = 0;
 | 
				
			||||||
        return AUDIO_S8;
 | 
					        return AUDIO_S8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_U8:
 | 
					    case AUD_FMT_U8:
 | 
				
			||||||
 | 
					        *shift = 0;
 | 
				
			||||||
        return AUDIO_U8;
 | 
					        return AUDIO_U8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_S16:
 | 
					    case AUD_FMT_S16:
 | 
				
			||||||
 | 
					        *shift = 1;
 | 
				
			||||||
        return AUDIO_S16LSB;
 | 
					        return AUDIO_S16LSB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUD_FMT_U16:
 | 
					    case AUD_FMT_U16:
 | 
				
			||||||
 | 
					        *shift = 1;
 | 
				
			||||||
        return AUDIO_U16LSB;
 | 
					        return AUDIO_U16LSB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default:
 | 
					    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) {
 | 
					    switch (sdlfmt) {
 | 
				
			||||||
    case AUDIO_S8:
 | 
					    case AUDIO_S8:
 | 
				
			||||||
        *endianness = 0;
 | 
					        *endianess = 0;
 | 
				
			||||||
        *fmt = AUD_FMT_S8;
 | 
					        *fmt = AUD_FMT_S8;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUDIO_U8:
 | 
					    case AUDIO_U8:
 | 
				
			||||||
        *endianness = 0;
 | 
					        *endianess = 0;
 | 
				
			||||||
        *fmt = AUD_FMT_U8;
 | 
					        *fmt = AUD_FMT_U8;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUDIO_S16LSB:
 | 
					    case AUDIO_S16LSB:
 | 
				
			||||||
        *endianness = 0;
 | 
					        *endianess = 0;
 | 
				
			||||||
        *fmt = AUD_FMT_S16;
 | 
					        *fmt = AUD_FMT_S16;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUDIO_U16LSB:
 | 
					    case AUDIO_U16LSB:
 | 
				
			||||||
        *endianness = 0;
 | 
					        *endianess = 0;
 | 
				
			||||||
        *fmt = AUD_FMT_U16;
 | 
					        *fmt = AUD_FMT_U16;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUDIO_S16MSB:
 | 
					    case AUDIO_S16MSB:
 | 
				
			||||||
        *endianness = 1;
 | 
					        *endianess = 1;
 | 
				
			||||||
        *fmt = AUD_FMT_S16;
 | 
					        *fmt = AUD_FMT_S16;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case AUDIO_U16MSB:
 | 
					    case AUDIO_U16MSB:
 | 
				
			||||||
        *endianness = 1;
 | 
					        *endianess = 1;
 | 
				
			||||||
        *fmt = AUD_FMT_U16;
 | 
					        *fmt = AUD_FMT_U16;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -183,20 +188,11 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    int status;
 | 
					    int status;
 | 
				
			||||||
#ifndef _WIN32
 | 
					#ifndef _WIN32
 | 
				
			||||||
    int err;
 | 
					 | 
				
			||||||
    sigset_t new, old;
 | 
					    sigset_t new, old;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Make sure potential threads created by SDL don't hog signals.  */
 | 
					    /* Make sure potential threads created by SDL don't hog signals.  */
 | 
				
			||||||
    err = sigfillset (&new);
 | 
					    sigfillset (&new);
 | 
				
			||||||
    if (err) {
 | 
					    pthread_sigmask (SIG_BLOCK, &new, &old);
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    status = SDL_OpenAudio (req, obt);
 | 
					    status = SDL_OpenAudio (req, obt);
 | 
				
			||||||
@@ -205,14 +201,7 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _WIN32
 | 
					#ifndef _WIN32
 | 
				
			||||||
    err = pthread_sigmask (SIG_SETMASK, &old, NULL);
 | 
					    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);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    return status;
 | 
					    return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -236,6 +225,10 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
 | 
				
			|||||||
    HWVoiceOut *hw = &sdl->hw;
 | 
					    HWVoiceOut *hw = &sdl->hw;
 | 
				
			||||||
    int samples = len >> hw->info.shift;
 | 
					    int samples = len >> hw->info.shift;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (sdl_lock (s, "sdl_callback")) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->exit) {
 | 
					    if (s->exit) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -243,49 +236,34 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
 | 
				
			|||||||
    while (samples) {
 | 
					    while (samples) {
 | 
				
			||||||
        int to_mix, decr;
 | 
					        int to_mix, decr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* dolog ("in callback samples=%d\n", samples); */
 | 
					        while (!sdl->pending) {
 | 
				
			||||||
        sdl_wait (s, "sdl_callback");
 | 
					            if (sdl_unlock (s, "sdl_callback")) {
 | 
				
			||||||
        if (s->exit) {
 | 
					                return;
 | 
				
			||||||
            return;
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sdl_wait (s, "sdl_callback");
 | 
				
			||||||
 | 
					            if (s->exit) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (sdl_lock (s, "sdl_callback")) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sdl->pending += sdl->live;
 | 
				
			||||||
 | 
					            sdl->live = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sdl_lock (s, "sdl_callback")) {
 | 
					        to_mix = audio_MIN (samples, sdl->pending);
 | 
				
			||||||
            return;
 | 
					        decr = audio_pcm_hw_clip_out (hw, buf, to_mix, 0);
 | 
				
			||||||
        }
 | 
					        buf += decr << hw->info.shift;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        samples -= decr;
 | 
					        samples -= decr;
 | 
				
			||||||
        sdl->live -= decr;
 | 
					 | 
				
			||||||
        sdl->decr += decr;
 | 
					        sdl->decr += decr;
 | 
				
			||||||
 | 
					        sdl->pending -= decr;
 | 
				
			||||||
    again:
 | 
					    }
 | 
				
			||||||
        if (sdl_unlock (s, "sdl_callback")) {
 | 
					
 | 
				
			||||||
            return;
 | 
					    if (sdl_unlock (s, "sdl_callback")) {
 | 
				
			||||||
        }
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /* dolog ("done len=%d\n", len); */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int sdl_write_out (SWVoiceOut *sw, void *buf, int 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;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (sdl->decr > live) {
 | 
					    sdl->live = live;
 | 
				
			||||||
        ldebug ("sdl->decr %d live %d sdl->live %d\n",
 | 
					    decr = sdl->decr;
 | 
				
			||||||
                sdl->decr,
 | 
					    sdl->decr = 0;
 | 
				
			||||||
                live,
 | 
					 | 
				
			||||||
                sdl->live);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    decr = audio_MIN (sdl->decr, live);
 | 
					 | 
				
			||||||
    sdl->decr -= decr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sdl->live = live - decr;
 | 
					 | 
				
			||||||
    hw->rpos = sdl->rpos;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (sdl->live > 0) {
 | 
					    if (sdl->live > 0) {
 | 
				
			||||||
        sdl_unlock_and_post (s, "sdl_run_out");
 | 
					        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;
 | 
					    SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
 | 
				
			||||||
    SDLAudioState *s = &glob_sdl;
 | 
					    SDLAudioState *s = &glob_sdl;
 | 
				
			||||||
    SDL_AudioSpec req, obt;
 | 
					    SDL_AudioSpec req, obt;
 | 
				
			||||||
    int endianness;
 | 
					    int shift;
 | 
				
			||||||
 | 
					    int endianess;
 | 
				
			||||||
    int err;
 | 
					    int err;
 | 
				
			||||||
    audfmt_e effective_fmt;
 | 
					    audfmt_e effective_fmt;
 | 
				
			||||||
    struct audsettings obt_as;
 | 
					    struct audsettings obt_as;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shift <<= as->nchannels == 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    req.freq = as->freq;
 | 
					    req.freq = as->freq;
 | 
				
			||||||
    req.format = aud_to_sdlfmt (as->fmt);
 | 
					    req.format = aud_to_sdlfmt (as->fmt, &shift);
 | 
				
			||||||
    req.channels = as->nchannels;
 | 
					    req.channels = as->nchannels;
 | 
				
			||||||
    req.samples = conf.nb_samples;
 | 
					    req.samples = conf.nb_samples;
 | 
				
			||||||
    req.callback = sdl_callback;
 | 
					    req.callback = sdl_callback;
 | 
				
			||||||
@@ -353,7 +325,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
 | 
					    err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
 | 
				
			||||||
    if (err) {
 | 
					    if (err) {
 | 
				
			||||||
        sdl_close (s);
 | 
					        sdl_close (s);
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
@@ -362,7 +334,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
    obt_as.freq = obt.freq;
 | 
					    obt_as.freq = obt.freq;
 | 
				
			||||||
    obt_as.nchannels = obt.channels;
 | 
					    obt_as.nchannels = obt.channels;
 | 
				
			||||||
    obt_as.fmt = effective_fmt;
 | 
					    obt_as.fmt = effective_fmt;
 | 
				
			||||||
    obt_as.endianness = endianness;
 | 
					    obt_as.endianness = endianess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    audio_pcm_init_info (&hw->info, &obt_as);
 | 
					    audio_pcm_init_info (&hw->info, &obt_as);
 | 
				
			||||||
    hw->samples = obt.samples;
 | 
					    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 {
 | 
					typedef struct WAVVoiceOut {
 | 
				
			||||||
    HWVoiceOut hw;
 | 
					    HWVoiceOut hw;
 | 
				
			||||||
    FILE *f;
 | 
					    QEMUFile *f;
 | 
				
			||||||
    int64_t old_ticks;
 | 
					    int64_t old_ticks;
 | 
				
			||||||
    void *pcm_buf;
 | 
					    void *pcm_buf;
 | 
				
			||||||
    int total_samples;
 | 
					    int total_samples;
 | 
				
			||||||
@@ -52,7 +52,7 @@ static int wav_run_out (HWVoiceOut *hw, int live)
 | 
				
			|||||||
    int rpos, decr, samples;
 | 
					    int rpos, decr, samples;
 | 
				
			||||||
    uint8_t *dst;
 | 
					    uint8_t *dst;
 | 
				
			||||||
    struct st_sample *src;
 | 
					    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 ticks = now - wav->old_ticks;
 | 
				
			||||||
    int64_t bytes =
 | 
					    int64_t bytes =
 | 
				
			||||||
        muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
 | 
					        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);
 | 
					        dst = advance (wav->pcm_buf, rpos << hw->info.shift);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        hw->clip (dst, src, convert_samples);
 | 
					        hw->clip (dst, src, convert_samples);
 | 
				
			||||||
        if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) {
 | 
					        qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
 | 
				
			||||||
            dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n",
 | 
					 | 
				
			||||||
                   convert_samples << hw->info.shift, strerror (errno));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        rpos = (rpos + convert_samples) % hw->samples;
 | 
					        rpos = (rpos + convert_samples) % hw->samples;
 | 
				
			||||||
        samples -= convert_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 + 28, hw->info.freq << (bits16 + stereo), 4);
 | 
				
			||||||
    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
 | 
					    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) {
 | 
					    if (!wav->f) {
 | 
				
			||||||
        dolog ("Failed to open wave file `%s'\nReason: %s\n",
 | 
					        dolog ("Failed to open wave file `%s'\nReason: %s\n",
 | 
				
			||||||
               conf.wav_path, strerror (errno));
 | 
					               conf.wav_path, strerror (errno));
 | 
				
			||||||
        g_free (wav->pcm_buf);
 | 
					        qemu_free (wav->pcm_buf);
 | 
				
			||||||
        wav->pcm_buf = NULL;
 | 
					        wav->pcm_buf = NULL;
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
 | 
					    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
 | 
				
			||||||
        dolog ("wav_init_out: failed to write header\nReason: %s\n",
 | 
					 | 
				
			||||||
               strerror(errno));
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -187,35 +180,16 @@ static void wav_fini_out (HWVoiceOut *hw)
 | 
				
			|||||||
    le_store (rlen, rifflen, 4);
 | 
					    le_store (rlen, rifflen, 4);
 | 
				
			||||||
    le_store (dlen, datalen, 4);
 | 
					    le_store (dlen, datalen, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (fseek (wav->f, 4, SEEK_SET)) {
 | 
					    qemu_fseek (wav->f, 4, SEEK_SET);
 | 
				
			||||||
        dolog ("wav_fini_out: fseek to rlen failed\nReason: %s\n",
 | 
					    qemu_put_buffer (wav->f, rlen, 4);
 | 
				
			||||||
               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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 doclose:
 | 
					    qemu_fseek (wav->f, 32, SEEK_CUR);
 | 
				
			||||||
    if (fclose (wav->f))  {
 | 
					    qemu_put_buffer (wav->f, dlen, 4);
 | 
				
			||||||
        dolog ("wav_fini_out: fclose %p failed\nReason: %s\n",
 | 
					
 | 
				
			||||||
               wav->f, strerror (errno));
 | 
					    qemu_fclose (wav->f);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    wav->f = NULL;
 | 
					    wav->f = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (wav->pcm_buf);
 | 
					    qemu_free (wav->pcm_buf);
 | 
				
			||||||
    wav->pcm_buf = NULL;
 | 
					    wav->pcm_buf = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
#include "audio.h"
 | 
					#include "audio.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    FILE *f;
 | 
					    QEMUFile *f;
 | 
				
			||||||
    int bytes;
 | 
					    int bytes;
 | 
				
			||||||
    char *path;
 | 
					    char *path;
 | 
				
			||||||
    int freq;
 | 
					    int freq;
 | 
				
			||||||
@@ -35,50 +35,27 @@ static void wav_destroy (void *opaque)
 | 
				
			|||||||
    uint8_t dlen[4];
 | 
					    uint8_t dlen[4];
 | 
				
			||||||
    uint32_t datalen = wav->bytes;
 | 
					    uint32_t datalen = wav->bytes;
 | 
				
			||||||
    uint32_t rifflen = datalen + 36;
 | 
					    uint32_t rifflen = datalen + 36;
 | 
				
			||||||
    Monitor *mon = cur_mon;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (wav->f) {
 | 
					    if (wav->f) {
 | 
				
			||||||
        le_store (rlen, rifflen, 4);
 | 
					        le_store (rlen, rifflen, 4);
 | 
				
			||||||
        le_store (dlen, datalen, 4);
 | 
					        le_store (dlen, datalen, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (fseek (wav->f, 4, SEEK_SET)) {
 | 
					        qemu_fseek (wav->f, 4, SEEK_SET);
 | 
				
			||||||
            monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
 | 
					        qemu_put_buffer (wav->f, rlen, 4);
 | 
				
			||||||
                            strerror (errno));
 | 
					
 | 
				
			||||||
            goto doclose;
 | 
					        qemu_fseek (wav->f, 32, SEEK_CUR);
 | 
				
			||||||
        }
 | 
					        qemu_put_buffer (wav->f, dlen, 4);
 | 
				
			||||||
        if (fwrite (rlen, 4, 1, wav->f) != 1) {
 | 
					        qemu_fclose (wav->f);
 | 
				
			||||||
            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));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (wav->path);
 | 
					    qemu_free (wav->path);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wav_capture (void *opaque, void *buf, int size)
 | 
					static void wav_capture (void *opaque, void *buf, int size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    WAVState *wav = opaque;
 | 
					    WAVState *wav = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (fwrite (buf, size, 1, wav->f) != 1) {
 | 
					    qemu_put_buffer (wav->f, buf, size);
 | 
				
			||||||
        monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
 | 
					 | 
				
			||||||
                        strerror (errno));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    wav->bytes += size;
 | 
					    wav->bytes += size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,9 +71,9 @@ static void wav_capture_info (void *opaque)
 | 
				
			|||||||
    WAVState *wav = opaque;
 | 
					    WAVState *wav = opaque;
 | 
				
			||||||
    char *path = wav->path;
 | 
					    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,
 | 
					                   wav->freq, wav->bits, wav->nchannels,
 | 
				
			||||||
                    path ? path : "<not available>", wav->bytes);
 | 
					                   path ? path : "<not available>", wav->bytes);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct capture_ops wav_capture_ops = {
 | 
					static struct capture_ops wav_capture_ops = {
 | 
				
			||||||
@@ -121,13 +98,13 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
 | 
				
			|||||||
    CaptureVoiceOut *cap;
 | 
					    CaptureVoiceOut *cap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (bits != 8 && bits != 16) {
 | 
					    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;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nchannels != 1 && nchannels != 2) {
 | 
					    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);
 | 
					                       nchannels);
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -143,7 +120,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
 | 
				
			|||||||
    ops.capture = wav_capture;
 | 
					    ops.capture = wav_capture;
 | 
				
			||||||
    ops.destroy = wav_destroy;
 | 
					    ops.destroy = wav_destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wav = g_malloc0 (sizeof (*wav));
 | 
					    wav = qemu_mallocz (sizeof (*wav));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    shift = bits16 + stereo;
 | 
					    shift = bits16 + stereo;
 | 
				
			||||||
    hdr[34] = bits16 ? 0x10 : 0x08;
 | 
					    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 + 28, freq << shift, 4);
 | 
				
			||||||
    le_store (hdr + 32, 1 << shift, 2);
 | 
					    le_store (hdr + 32, 1 << shift, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wav->f = fopen (path, "wb");
 | 
					    wav->f = qemu_fopen (path, "wb");
 | 
				
			||||||
    if (!wav->f) {
 | 
					    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));
 | 
					                       path, strerror (errno));
 | 
				
			||||||
        g_free (wav);
 | 
					        qemu_free (wav);
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wav->path = g_strdup (path);
 | 
					    wav->path = qemu_strdup (path);
 | 
				
			||||||
    wav->bits = bits;
 | 
					    wav->bits = bits;
 | 
				
			||||||
    wav->nchannels = nchannels;
 | 
					    wav->nchannels = nchannels;
 | 
				
			||||||
    wav->freq = freq;
 | 
					    wav->freq = freq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
 | 
					    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
 | 
				
			||||||
        monitor_printf (mon, "Failed to write header\nReason: %s\n",
 | 
					 | 
				
			||||||
                        strerror (errno));
 | 
					 | 
				
			||||||
        goto error_free;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cap = AUD_add_capture (&as, &ops, wav);
 | 
					    cap = AUD_add_capture (&as, &ops, wav);
 | 
				
			||||||
    if (!cap) {
 | 
					    if (!cap) {
 | 
				
			||||||
        monitor_printf (mon, "Failed to add audio capture\n");
 | 
					        monitor_printf(mon, "Failed to add audio capture\n");
 | 
				
			||||||
        goto error_free;
 | 
					        qemu_free (wav->path);
 | 
				
			||||||
 | 
					        qemu_fclose (wav->f);
 | 
				
			||||||
 | 
					        qemu_free (wav);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wav->cap = cap;
 | 
					    wav->cap = cap;
 | 
				
			||||||
    s->opaque = wav;
 | 
					    s->opaque = wav;
 | 
				
			||||||
    s->ops = wav_capture_ops;
 | 
					    s->ops = wav_capture_ops;
 | 
				
			||||||
    return 0;
 | 
					    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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,7 +72,7 @@ static void winwave_log_mmresult (MMRESULT mr)
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case MMSYSERR_NOMEM:
 | 
					    case MMSYSERR_NOMEM:
 | 
				
			||||||
        str = "Unable to allocate or lock memory";
 | 
					        str = "Unable to allocate or locl memory";
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case WAVERR_SYNC:
 | 
					    case WAVERR_SYNC:
 | 
				
			||||||
@@ -222,9 +222,9 @@ static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 err4:
 | 
					 err4:
 | 
				
			||||||
    g_free (wave->pcm_buf);
 | 
					    qemu_free (wave->pcm_buf);
 | 
				
			||||||
 err3:
 | 
					 err3:
 | 
				
			||||||
    g_free (wave->hdrs);
 | 
					    qemu_free (wave->hdrs);
 | 
				
			||||||
 err2:
 | 
					 err2:
 | 
				
			||||||
    winwave_anal_close_out (wave);
 | 
					    winwave_anal_close_out (wave);
 | 
				
			||||||
 err1:
 | 
					 err1:
 | 
				
			||||||
@@ -310,10 +310,10 @@ static void winwave_fini_out (HWVoiceOut *hw)
 | 
				
			|||||||
        wave->event = NULL;
 | 
					        wave->event = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (wave->pcm_buf);
 | 
					    qemu_free (wave->pcm_buf);
 | 
				
			||||||
    wave->pcm_buf = NULL;
 | 
					    wave->pcm_buf = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (wave->hdrs);
 | 
					    qemu_free (wave->hdrs);
 | 
				
			||||||
    wave->hdrs = NULL;
 | 
					    wave->hdrs = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -511,9 +511,9 @@ static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 err4:
 | 
					 err4:
 | 
				
			||||||
    g_free (wave->pcm_buf);
 | 
					    qemu_free (wave->pcm_buf);
 | 
				
			||||||
 err3:
 | 
					 err3:
 | 
				
			||||||
    g_free (wave->hdrs);
 | 
					    qemu_free (wave->hdrs);
 | 
				
			||||||
 err2:
 | 
					 err2:
 | 
				
			||||||
    winwave_anal_close_in (wave);
 | 
					    winwave_anal_close_in (wave);
 | 
				
			||||||
 err1:
 | 
					 err1:
 | 
				
			||||||
@@ -550,10 +550,10 @@ static void winwave_fini_in (HWVoiceIn *hw)
 | 
				
			|||||||
        wave->event = NULL;
 | 
					        wave->event = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (wave->pcm_buf);
 | 
					    qemu_free (wave->pcm_buf);
 | 
				
			||||||
    wave->pcm_buf = NULL;
 | 
					    wave->pcm_buf = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_free (wave->hdrs);
 | 
					    qemu_free (wave->hdrs);
 | 
				
			||||||
    wave->hdrs = NULL;
 | 
					    wave->hdrs = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -581,7 +581,8 @@ static int winwave_run_in (HWVoiceIn *hw)
 | 
				
			|||||||
        int conv = audio_MIN (left, decr);
 | 
					        int conv = audio_MIN (left, decr);
 | 
				
			||||||
        hw->conv (hw->conv_buf + hw->wpos,
 | 
					        hw->conv (hw->conv_buf + hw->wpos,
 | 
				
			||||||
                  advance (wave->pcm_buf, wave->rpos << hw->info.shift),
 | 
					                  advance (wave->pcm_buf, wave->rpos << hw->info.shift),
 | 
				
			||||||
                  conv);
 | 
					                  conv,
 | 
				
			||||||
 | 
					                  &nominal_volume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wave->rpos = (wave->rpos + conv) % hw->samples;
 | 
					        wave->rpos = (wave->rpos + conv) % hw->samples;
 | 
				
			||||||
        hw->wpos = (hw->wpos + conv) % hw->samples;
 | 
					        hw->wpos = (hw->wpos + conv) % hw->samples;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										132
									
								
								balloon.c
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								balloon.c
									
									
									
									
									
								
							@@ -1,132 +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"
 | 
					 | 
				
			||||||
#include "qjson.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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void qemu_balloon_changed(int64_t actual)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    QObject *data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    data = qobject_from_jsonf("{ 'actual': %" PRId64 " }",
 | 
					 | 
				
			||||||
                              actual);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    monitor_protocol_event(QEVENT_BALLOON_CHANGE, data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    qobject_decref(data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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,16 +14,14 @@
 | 
				
			|||||||
#ifndef _QEMU_BALLOON_H
 | 
					#ifndef _QEMU_BALLOON_H
 | 
				
			||||||
#define _QEMU_BALLOON_H
 | 
					#define _QEMU_BALLOON_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "monitor.h"
 | 
					#include "cpu-defs.h"
 | 
				
			||||||
#include "qapi-types.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
 | 
					typedef ram_addr_t (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
 | 
				
			||||||
typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
 | 
					void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
 | 
				
			||||||
			     QEMUBalloonStatus *stat_func, void *opaque);
 | 
					 | 
				
			||||||
void qemu_remove_balloon_handler(void *opaque);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qemu_balloon_changed(int64_t actual);
 | 
					void qemu_balloon(ram_addr_t target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ram_addr_t qemu_balloon_status(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										362
									
								
								bitops.h
									
									
									
									
									
								
							
							
						
						
									
										362
									
								
								bitops.h
									
									
									
									
									
								
							@@ -1,362 +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, unsigned long *addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long mask = BIT_MASK(nr);
 | 
					 | 
				
			||||||
        unsigned long *p = 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, unsigned long *addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long mask = BIT_MASK(nr);
 | 
					 | 
				
			||||||
        unsigned long *p = 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, unsigned long *addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long mask = BIT_MASK(nr);
 | 
					 | 
				
			||||||
        unsigned long *p = 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, unsigned long *addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long mask = BIT_MASK(nr);
 | 
					 | 
				
			||||||
        unsigned long *p = 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, unsigned long *addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long mask = BIT_MASK(nr);
 | 
					 | 
				
			||||||
        unsigned long *p = 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, unsigned long *addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long mask = BIT_MASK(nr);
 | 
					 | 
				
			||||||
        unsigned long *p = 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 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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * extract32:
 | 
					 | 
				
			||||||
 * @value: the value to extract the bit field from
 | 
					 | 
				
			||||||
 * @start: the lowest bit in the bit field (numbered from 0)
 | 
					 | 
				
			||||||
 * @length: the length of the bit field
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Extract from the 32 bit input @value the bit field specified by the
 | 
					 | 
				
			||||||
 * @start and @length parameters, and return it. The bit field must
 | 
					 | 
				
			||||||
 * lie entirely within the 32 bit word. It is valid to request that
 | 
					 | 
				
			||||||
 * all 32 bits are returned (ie @length 32 and @start 0).
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns: the value of the bit field extracted from the input value.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static inline uint32_t extract32(uint32_t value, int start, int length)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    assert(start >= 0 && length > 0 && length <= 32 - start);
 | 
					 | 
				
			||||||
    return (value >> start) & (~0U >> (32 - length));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * extract64:
 | 
					 | 
				
			||||||
 * @value: the value to extract the bit field from
 | 
					 | 
				
			||||||
 * @start: the lowest bit in the bit field (numbered from 0)
 | 
					 | 
				
			||||||
 * @length: the length of the bit field
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Extract from the 64 bit input @value the bit field specified by the
 | 
					 | 
				
			||||||
 * @start and @length parameters, and return it. The bit field must
 | 
					 | 
				
			||||||
 * lie entirely within the 64 bit word. It is valid to request that
 | 
					 | 
				
			||||||
 * all 64 bits are returned (ie @length 64 and @start 0).
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns: the value of the bit field extracted from the input value.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static inline uint64_t extract64(uint64_t value, int start, int length)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    assert(start >= 0 && length > 0 && length <= 64 - start);
 | 
					 | 
				
			||||||
    return (value >> start) & (~0ULL >> (64 - length));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * deposit32:
 | 
					 | 
				
			||||||
 * @value: initial value to insert bit field into
 | 
					 | 
				
			||||||
 * @start: the lowest bit in the bit field (numbered from 0)
 | 
					 | 
				
			||||||
 * @length: the length of the bit field
 | 
					 | 
				
			||||||
 * @fieldval: the value to insert into the bit field
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Deposit @fieldval into the 32 bit @value at the bit field specified
 | 
					 | 
				
			||||||
 * by the @start and @length parameters, and return the modified
 | 
					 | 
				
			||||||
 * @value. Bits of @value outside the bit field are not modified.
 | 
					 | 
				
			||||||
 * Bits of @fieldval above the least significant @length bits are
 | 
					 | 
				
			||||||
 * ignored. The bit field must lie entirely within the 32 bit word.
 | 
					 | 
				
			||||||
 * It is valid to request that all 32 bits are modified (ie @length
 | 
					 | 
				
			||||||
 * 32 and @start 0).
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns: the modified @value.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static inline uint32_t deposit32(uint32_t value, int start, int length,
 | 
					 | 
				
			||||||
                                 uint32_t fieldval)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uint32_t mask;
 | 
					 | 
				
			||||||
    assert(start >= 0 && length > 0 && length <= 32 - start);
 | 
					 | 
				
			||||||
    mask = (~0U >> (32 - length)) << start;
 | 
					 | 
				
			||||||
    return (value & ~mask) | ((fieldval << start) & mask);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * deposit64:
 | 
					 | 
				
			||||||
 * @value: initial value to insert bit field into
 | 
					 | 
				
			||||||
 * @start: the lowest bit in the bit field (numbered from 0)
 | 
					 | 
				
			||||||
 * @length: the length of the bit field
 | 
					 | 
				
			||||||
 * @fieldval: the value to insert into the bit field
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Deposit @fieldval into the 64 bit @value at the bit field specified
 | 
					 | 
				
			||||||
 * by the @start and @length parameters, and return the modified
 | 
					 | 
				
			||||||
 * @value. Bits of @value outside the bit field are not modified.
 | 
					 | 
				
			||||||
 * Bits of @fieldval above the least significant @length bits are
 | 
					 | 
				
			||||||
 * ignored. The bit field must lie entirely within the 64 bit word.
 | 
					 | 
				
			||||||
 * It is valid to request that all 64 bits are modified (ie @length
 | 
					 | 
				
			||||||
 * 64 and @start 0).
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns: the modified @value.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static inline uint64_t deposit64(uint64_t value, int start, int length,
 | 
					 | 
				
			||||||
                                 uint64_t fieldval)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uint64_t mask;
 | 
					 | 
				
			||||||
    assert(start >= 0 && length > 0 && length <= 64 - start);
 | 
					 | 
				
			||||||
    mask = (~0ULL >> (64 - length)) << start;
 | 
					 | 
				
			||||||
    return (value & ~mask) | ((fieldval << start) & mask);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@@ -9,18 +9,14 @@
 | 
				
			|||||||
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
					 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
				
			||||||
 * the COPYING file in the top-level directory.
 | 
					 * 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 "qemu-common.h"
 | 
				
			||||||
#include "block_int.h"
 | 
					#include "block_int.h"
 | 
				
			||||||
#include "hw/hw.h"
 | 
					#include "hw/hw.h"
 | 
				
			||||||
#include "qemu-queue.h"
 | 
					#include "qemu-queue.h"
 | 
				
			||||||
#include "qemu-timer.h"
 | 
					#include "monitor.h"
 | 
				
			||||||
#include "block-migration.h"
 | 
					#include "block-migration.h"
 | 
				
			||||||
#include "migration.h"
 | 
					 | 
				
			||||||
#include "blockdev.h"
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
 | 
					#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
 | 
				
			||||||
@@ -30,14 +26,17 @@
 | 
				
			|||||||
#define BLK_MIG_FLAG_PROGRESS           0x04
 | 
					#define BLK_MIG_FLAG_PROGRESS           0x04
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_IS_ALLOCATED_SEARCH 65536
 | 
					#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
 | 
					//#define DEBUG_BLK_MIGRATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG_BLK_MIGRATION
 | 
					#ifdef DEBUG_BLK_MIGRATION
 | 
				
			||||||
#define DPRINTF(fmt, ...) \
 | 
					#define dprintf(fmt, ...) \
 | 
				
			||||||
    do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0)
 | 
					    do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define DPRINTF(fmt, ...) \
 | 
					#define dprintf(fmt, ...) \
 | 
				
			||||||
    do { } while (0)
 | 
					    do { } while (0)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,19 +45,16 @@ typedef struct BlkMigDevState {
 | 
				
			|||||||
    int bulk_completed;
 | 
					    int bulk_completed;
 | 
				
			||||||
    int shared_base;
 | 
					    int shared_base;
 | 
				
			||||||
    int64_t cur_sector;
 | 
					    int64_t cur_sector;
 | 
				
			||||||
    int64_t cur_dirty;
 | 
					 | 
				
			||||||
    int64_t completed_sectors;
 | 
					    int64_t completed_sectors;
 | 
				
			||||||
    int64_t total_sectors;
 | 
					    int64_t total_sectors;
 | 
				
			||||||
    int64_t dirty;
 | 
					    int64_t dirty;
 | 
				
			||||||
    QSIMPLEQ_ENTRY(BlkMigDevState) entry;
 | 
					    QSIMPLEQ_ENTRY(BlkMigDevState) entry;
 | 
				
			||||||
    unsigned long *aio_bitmap;
 | 
					 | 
				
			||||||
} BlkMigDevState;
 | 
					} BlkMigDevState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct BlkMigBlock {
 | 
					typedef struct BlkMigBlock {
 | 
				
			||||||
    uint8_t *buf;
 | 
					    uint8_t *buf;
 | 
				
			||||||
    BlkMigDevState *bmds;
 | 
					    BlkMigDevState *bmds;
 | 
				
			||||||
    int64_t sector;
 | 
					    int64_t sector;
 | 
				
			||||||
    int nr_sectors;
 | 
					 | 
				
			||||||
    struct iovec iov;
 | 
					    struct iovec iov;
 | 
				
			||||||
    QEMUIOVector qiov;
 | 
					    QEMUIOVector qiov;
 | 
				
			||||||
    BlockDriverAIOCB *aiocb;
 | 
					    BlockDriverAIOCB *aiocb;
 | 
				
			||||||
@@ -76,10 +72,6 @@ typedef struct BlkMigState {
 | 
				
			|||||||
    int transferred;
 | 
					    int transferred;
 | 
				
			||||||
    int64_t total_sector_sum;
 | 
					    int64_t total_sector_sum;
 | 
				
			||||||
    int prev_progress;
 | 
					    int prev_progress;
 | 
				
			||||||
    int bulk_completed;
 | 
					 | 
				
			||||||
    long double total_time;
 | 
					 | 
				
			||||||
    long double prev_time_offset;
 | 
					 | 
				
			||||||
    int reads;
 | 
					 | 
				
			||||||
} BlkMigState;
 | 
					} BlkMigState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlkMigState block_mig_state;
 | 
					static BlkMigState block_mig_state;
 | 
				
			||||||
@@ -132,78 +124,21 @@ uint64_t blk_mig_bytes_total(void)
 | 
				
			|||||||
    return sum << BDRV_SECTOR_BITS;
 | 
					    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)
 | 
					static void blk_mig_read_cb(void *opaque, int ret)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    long double curr_time = qemu_get_clock_ns(rt_clock);
 | 
					 | 
				
			||||||
    BlkMigBlock *blk = opaque;
 | 
					    BlkMigBlock *blk = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    blk->ret = ret;
 | 
					    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);
 | 
					    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.submitted--;
 | 
				
			||||||
    block_mig_state.read_done++;
 | 
					    block_mig_state.read_done++;
 | 
				
			||||||
    assert(block_mig_state.submitted >= 0);
 | 
					    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 total_sectors = bmds->total_sectors;
 | 
				
			||||||
    int64_t cur_sector = bmds->cur_sector;
 | 
					    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;
 | 
					        nr_sectors = total_sectors - cur_sector;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    blk = g_malloc(sizeof(BlkMigBlock));
 | 
					    blk = qemu_malloc(sizeof(BlkMigBlock));
 | 
				
			||||||
    blk->buf = g_malloc(BLOCK_SIZE);
 | 
					    blk->buf = qemu_malloc(BLOCK_SIZE);
 | 
				
			||||||
    blk->bmds = bmds;
 | 
					    blk->bmds = bmds;
 | 
				
			||||||
    blk->sector = cur_sector;
 | 
					    blk->sector = cur_sector;
 | 
				
			||||||
    blk->nr_sectors = nr_sectors;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    blk->iov.iov_base = blk->buf;
 | 
					    if (is_async) {
 | 
				
			||||||
    blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
 | 
					        blk->iov.iov_base = blk->buf;
 | 
				
			||||||
    qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
 | 
					        blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
 | 
				
			||||||
 | 
					        qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (block_mig_state.submitted == 0) {
 | 
					        blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
 | 
				
			||||||
        block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
 | 
					                                    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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
 | 
					 | 
				
			||||||
                                nr_sectors, blk_mig_read_cb, blk);
 | 
					 | 
				
			||||||
    block_mig_state.submitted++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bdrv_reset_dirty(bs, cur_sector, nr_sectors);
 | 
					    bdrv_reset_dirty(bs, cur_sector, nr_sectors);
 | 
				
			||||||
    bmds->cur_sector = cur_sector + nr_sectors;
 | 
					    bmds->cur_sector = cur_sector + nr_sectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (bmds->cur_sector >= total_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)
 | 
					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;
 | 
					    BlkMigDevState *bmds;
 | 
				
			||||||
 | 
					    BlockDriverState *bs;
 | 
				
			||||||
    int64_t sectors;
 | 
					    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.submitted = 0;
 | 
				
			||||||
    block_mig_state.read_done = 0;
 | 
					    block_mig_state.read_done = 0;
 | 
				
			||||||
    block_mig_state.transferred = 0;
 | 
					    block_mig_state.transferred = 0;
 | 
				
			||||||
    block_mig_state.total_sector_sum = 0;
 | 
					    block_mig_state.total_sector_sum = 0;
 | 
				
			||||||
    block_mig_state.prev_progress = -1;
 | 
					    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;
 | 
					    int64_t completed_sector_sum = 0;
 | 
				
			||||||
    BlkMigDevState *bmds;
 | 
					    BlkMigDevState *bmds;
 | 
				
			||||||
@@ -325,7 +269,7 @@ static int blk_mig_save_bulked_block(QEMUFile *f)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
					    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
				
			||||||
        if (bmds->bulk_completed == 0) {
 | 
					        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 */
 | 
					                /* completed bulk section for this device */
 | 
				
			||||||
                bmds->bulk_completed = 1;
 | 
					                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;
 | 
				
			||||||
        progress = completed_sector_sum * 100 /
 | 
					 | 
				
			||||||
                   block_mig_state.total_sector_sum;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        progress = 100;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (progress != block_mig_state.prev_progress) {
 | 
					    if (progress != block_mig_state.prev_progress) {
 | 
				
			||||||
        block_mig_state.prev_progress = progress;
 | 
					        block_mig_state.prev_progress = progress;
 | 
				
			||||||
        qemu_put_be64(f, (progress << BDRV_SECTOR_BITS)
 | 
					        qemu_put_be64(f, (progress << BDRV_SECTOR_BITS)
 | 
				
			||||||
                         | BLK_MIG_FLAG_PROGRESS);
 | 
					                         | BLK_MIG_FLAG_PROGRESS);
 | 
				
			||||||
        DPRINTF("Completed %d %%\r", progress);
 | 
					        monitor_printf(mon, "Completed %d %%\r", progress);
 | 
				
			||||||
 | 
					        monitor_flush(mon);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    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;
 | 
					    BlkMigDevState *bmds;
 | 
				
			||||||
 | 
					    BlkMigBlock blk;
 | 
				
			||||||
    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;
 | 
					    int64_t sector;
 | 
				
			||||||
    int nr_sectors;
 | 
					 | 
				
			||||||
    int ret = -EIO;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
 | 
					    blk.buf = qemu_malloc(BLOCK_SIZE);
 | 
				
			||||||
        if (bmds_aio_inflight(bmds, sector)) {
 | 
					 | 
				
			||||||
            bdrv_drain_all();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            blk = g_malloc(sizeof(BlkMigBlock));
 | 
					 | 
				
			||||||
            blk->buf = g_malloc(BLOCK_SIZE);
 | 
					 | 
				
			||||||
            blk->bmds = bmds;
 | 
					 | 
				
			||||||
            blk->sector = 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(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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        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) {
 | 
					    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
				
			||||||
        if (mig_save_device_dirty(f, bmds, is_async) == 0) {
 | 
					        for (sector = 0; sector < bmds->cur_sector;) {
 | 
				
			||||||
            ret = 1;
 | 
					            if (bdrv_get_dirty(bmds->bs, sector)) {
 | 
				
			||||||
            break;
 | 
					                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.bmds = bmds;
 | 
				
			||||||
 | 
					                blk.sector = sector;
 | 
				
			||||||
 | 
					                blk_send(f, &blk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                bdrv_reset_dirty(bmds->bs, sector,
 | 
				
			||||||
 | 
					                                 BDRV_SECTORS_PER_DIRTY_CHUNK);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    qemu_free(blk.buf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void flush_blks(QEMUFile* f)
 | 
					static void flush_blks(QEMUFile* f)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlkMigBlock *blk;
 | 
					    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,
 | 
					            __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
 | 
				
			||||||
            block_mig_state.transferred);
 | 
					            block_mig_state.transferred);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -457,204 +341,131 @@ static void flush_blks(QEMUFile* f)
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (blk->ret < 0) {
 | 
					        if (blk->ret < 0) {
 | 
				
			||||||
            qemu_file_set_error(f, blk->ret);
 | 
					            qemu_file_set_error(f);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        blk_send(f, blk);
 | 
					        blk_send(f, blk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
 | 
					        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
 | 
				
			||||||
        g_free(blk->buf);
 | 
					        qemu_free(blk->buf);
 | 
				
			||||||
        g_free(blk);
 | 
					        qemu_free(blk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        block_mig_state.read_done--;
 | 
					        block_mig_state.read_done--;
 | 
				
			||||||
        block_mig_state.transferred++;
 | 
					        block_mig_state.transferred++;
 | 
				
			||||||
        assert(block_mig_state.read_done >= 0);
 | 
					        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.submitted, block_mig_state.read_done,
 | 
				
			||||||
            block_mig_state.transferred);
 | 
					            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)
 | 
					static int is_stage2_completed(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t remaining_dirty;
 | 
					    BlkMigDevState *bmds;
 | 
				
			||||||
    long double bwidth;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (block_mig_state.bulk_completed == 1) {
 | 
					    if (block_mig_state.submitted > 0) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        remaining_dirty = get_remaining_dirty();
 | 
					    QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
 | 
				
			||||||
        if (remaining_dirty == 0) {
 | 
					        if (bmds->bulk_completed == 0) {
 | 
				
			||||||
            return 1;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void blk_mig_cleanup(void)
 | 
					static void blk_mig_cleanup(Monitor *mon)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BlkMigDevState *bmds;
 | 
					    BlkMigDevState *bmds;
 | 
				
			||||||
    BlkMigBlock *blk;
 | 
					    BlkMigBlock *blk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    set_dirty_tracking(0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
 | 
					    while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
 | 
				
			||||||
        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
 | 
					        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
 | 
				
			||||||
        bdrv_set_in_use(bmds->bs, 0);
 | 
					        qemu_free(bmds);
 | 
				
			||||||
        drive_put_ref(drive_get_by_blockdev(bmds->bs));
 | 
					 | 
				
			||||||
        g_free(bmds->aio_bitmap);
 | 
					 | 
				
			||||||
        g_free(bmds);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
 | 
					    while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
 | 
				
			||||||
        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
 | 
					        QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
 | 
				
			||||||
        g_free(blk->buf);
 | 
					        qemu_free(blk->buf);
 | 
				
			||||||
        g_free(blk);
 | 
					        qemu_free(blk);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set_dirty_tracking(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    monitor_printf(mon, "\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void block_migration_cancel(void *opaque)
 | 
					static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    blk_mig_cleanup();
 | 
					    dprintf("Enter save live stage %d submitted %d transferred %d\n",
 | 
				
			||||||
}
 | 
					            stage, block_mig_state.submitted, block_mig_state.transferred);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int block_save_setup(QEMUFile *f, void *opaque)
 | 
					    if (stage < 0) {
 | 
				
			||||||
{
 | 
					        blk_mig_cleanup(mon);
 | 
				
			||||||
    int ret;
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("Enter save live setup submitted %d transferred %d\n",
 | 
					    if (block_mig_state.blk_enable != 1) {
 | 
				
			||||||
            block_mig_state.submitted, block_mig_state.transferred);
 | 
					        /* no need to migrate storage */
 | 
				
			||||||
 | 
					        qemu_put_be64(f, BLK_MIG_FLAG_EOS);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init_blk_migration(f);
 | 
					    if (stage == 1) {
 | 
				
			||||||
 | 
					        init_blk_migration(mon, f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* start track dirty blocks */
 | 
					        /* start track dirty blocks */
 | 
				
			||||||
    set_dirty_tracking(1);
 | 
					        set_dirty_tracking(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    flush_blks(f);
 | 
					    flush_blks(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = qemu_file_get_error(f);
 | 
					    if (qemu_file_has_error(f)) {
 | 
				
			||||||
    if (ret) {
 | 
					        blk_mig_cleanup(mon);
 | 
				
			||||||
        blk_mig_cleanup();
 | 
					        return 0;
 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    blk_mig_reset_dirty_cursor();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    qemu_put_be64(f, BLK_MIG_FLAG_EOS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int block_save_iterate(QEMUFile *f, void *opaque)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DPRINTF("Enter save live iterate submitted %d transferred %d\n",
 | 
					 | 
				
			||||||
            block_mig_state.submitted, block_mig_state.transferred);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    flush_blks(f);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret = qemu_file_get_error(f);
 | 
					 | 
				
			||||||
    if (ret) {
 | 
					 | 
				
			||||||
        blk_mig_cleanup();
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    blk_mig_reset_dirty_cursor();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* control the rate of transfer */
 | 
					    /* control the rate of transfer */
 | 
				
			||||||
    while ((block_mig_state.submitted +
 | 
					    while ((block_mig_state.submitted +
 | 
				
			||||||
            block_mig_state.read_done) * BLOCK_SIZE <
 | 
					            block_mig_state.read_done) * BLOCK_SIZE <
 | 
				
			||||||
           qemu_file_get_rate_limit(f)) {
 | 
					           qemu_file_get_rate_limit(f)) {
 | 
				
			||||||
        if (block_mig_state.bulk_completed == 0) {
 | 
					        if (blk_mig_save_bulked_block(mon, f, 1) == 0) {
 | 
				
			||||||
            /* first finish the bulk phase */
 | 
					            /* no more bulk blocks for now */
 | 
				
			||||||
            if (blk_mig_save_bulked_block(f) == 0) {
 | 
					            break;
 | 
				
			||||||
                /* 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 */
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    flush_blks(f);
 | 
					    flush_blks(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = qemu_file_get_error(f);
 | 
					    if (qemu_file_has_error(f)) {
 | 
				
			||||||
    if (ret) {
 | 
					        blk_mig_cleanup(mon);
 | 
				
			||||||
        blk_mig_cleanup();
 | 
					        return 0;
 | 
				
			||||||
        return ret;
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (stage == 3) {
 | 
				
			||||||
 | 
					        while (blk_mig_save_bulked_block(mon, f, 0) != 0) {
 | 
				
			||||||
 | 
					            /* empty */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (qemu_file_has_error(f)) {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        monitor_printf(mon, "Block migration completed\n");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_put_be64(f, BLK_MIG_FLAG_EOS);
 | 
					    qemu_put_be64(f, BLK_MIG_FLAG_EOS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return is_stage2_completed();
 | 
					    return ((stage == 2) && is_stage2_completed());
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int block_save_complete(QEMUFile *f, void *opaque)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DPRINTF("Enter save live complete submitted %d transferred %d\n",
 | 
					 | 
				
			||||||
            block_mig_state.submitted, block_mig_state.transferred);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    flush_blks(f);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret = qemu_file_get_error(f);
 | 
					 | 
				
			||||||
    if (ret) {
 | 
					 | 
				
			||||||
        blk_mig_cleanup();
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    blk_mig_reset_dirty_cursor();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* we know for sure that save bulk is completed and
 | 
					 | 
				
			||||||
       all async read completed */
 | 
					 | 
				
			||||||
    assert(block_mig_state.submitted == 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (blk_mig_save_dirty_block(f, 0) != 0) {
 | 
					 | 
				
			||||||
        /* Do nothing */
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    blk_mig_cleanup();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* report completion */
 | 
					 | 
				
			||||||
    qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret = qemu_file_get_error(f);
 | 
					 | 
				
			||||||
    if (ret) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DPRINTF("Block migration completed\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    qemu_put_be64(f, BLK_MIG_FLAG_EOS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int block_load(QEMUFile *f, void *opaque, int version_id)
 | 
					static int block_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			||||||
@@ -663,11 +474,8 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
    int len, flags;
 | 
					    int len, flags;
 | 
				
			||||||
    char device_name[256];
 | 
					    char device_name[256];
 | 
				
			||||||
    int64_t addr;
 | 
					    int64_t addr;
 | 
				
			||||||
    BlockDriverState *bs, *bs_prev = NULL;
 | 
					    BlockDriverState *bs;
 | 
				
			||||||
    uint8_t *buf;
 | 
					    uint8_t *buf;
 | 
				
			||||||
    int64_t total_sectors = 0;
 | 
					 | 
				
			||||||
    int nr_sectors;
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
        addr = qemu_get_be64(f);
 | 
					        addr = qemu_get_be64(f);
 | 
				
			||||||
@@ -688,31 +496,12 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
                return -EINVAL;
 | 
					                return -EINVAL;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (bs != bs_prev) {
 | 
					            buf = qemu_malloc(BLOCK_SIZE);
 | 
				
			||||||
                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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            qemu_get_buffer(f, buf, 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);
 | 
					            qemu_free(buf);
 | 
				
			||||||
            if (ret < 0) {
 | 
					 | 
				
			||||||
                return ret;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if (flags & BLK_MIG_FLAG_PROGRESS) {
 | 
					        } else if (flags & BLK_MIG_FLAG_PROGRESS) {
 | 
				
			||||||
            if (!banner_printed) {
 | 
					            if (!banner_printed) {
 | 
				
			||||||
                printf("Receiving block device images\n");
 | 
					                printf("Receiving block device images\n");
 | 
				
			||||||
@@ -725,44 +514,28 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
            fprintf(stderr, "Unknown flags\n");
 | 
					            fprintf(stderr, "Unknown flags\n");
 | 
				
			||||||
            return -EINVAL;
 | 
					            return -EINVAL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ret = qemu_file_get_error(f);
 | 
					        if (qemu_file_has_error(f)) {
 | 
				
			||||||
        if (ret != 0) {
 | 
					            return -EIO;
 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } while (!(flags & BLK_MIG_FLAG_EOS));
 | 
					    } while (!(flags & BLK_MIG_FLAG_EOS));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void block_set_params(const MigrationParams *params, void *opaque)
 | 
					static void block_set_params(int blk_enable, int shared_base, void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    block_mig_state.blk_enable = params->blk;
 | 
					    block_mig_state.blk_enable = blk_enable;
 | 
				
			||||||
    block_mig_state.shared_base = params->shared;
 | 
					    block_mig_state.shared_base = shared_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* shared base means that blk_enable = 1 */
 | 
					    /* shared base means that blk_enable = 1 */
 | 
				
			||||||
    block_mig_state.blk_enable |= params->shared;
 | 
					    block_mig_state.blk_enable |= shared_base;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool block_is_active(void *opaque)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return block_mig_state.blk_enable == 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SaveVMHandlers savevm_block_handlers = {
 | 
					 | 
				
			||||||
    .set_params = block_set_params,
 | 
					 | 
				
			||||||
    .save_live_setup = block_save_setup,
 | 
					 | 
				
			||||||
    .save_live_iterate = block_save_iterate,
 | 
					 | 
				
			||||||
    .save_live_complete = block_save_complete,
 | 
					 | 
				
			||||||
    .load_state = block_load,
 | 
					 | 
				
			||||||
    .cancel = block_migration_cancel,
 | 
					 | 
				
			||||||
    .is_active = block_is_active,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void blk_mig_init(void)
 | 
					void blk_mig_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QSIMPLEQ_INIT(&block_mig_state.bmds_list);
 | 
					    QSIMPLEQ_INIT(&block_mig_state.bmds_list);
 | 
				
			||||||
    QSIMPLEQ_INIT(&block_mig_state.blk_list);
 | 
					    QSIMPLEQ_INIT(&block_mig_state.blk_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers,
 | 
					    register_savevm_live("block", 0, 1, block_set_params, block_save_live,
 | 
				
			||||||
                         &block_mig_state);
 | 
					                         NULL, block_load, &block_mig_state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										308
									
								
								block.h
									
									
									
									
									
								
							
							
						
						
									
										308
									
								
								block.h
									
									
									
									
									
								
							@@ -4,7 +4,6 @@
 | 
				
			|||||||
#include "qemu-aio.h"
 | 
					#include "qemu-aio.h"
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
#include "qemu-option.h"
 | 
					#include "qemu-option.h"
 | 
				
			||||||
#include "qemu-coroutine.h"
 | 
					 | 
				
			||||||
#include "qobject.h"
 | 
					#include "qobject.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* block.c */
 | 
					/* block.c */
 | 
				
			||||||
@@ -15,136 +14,63 @@ typedef struct BlockDriverInfo {
 | 
				
			|||||||
    int cluster_size;
 | 
					    int cluster_size;
 | 
				
			||||||
    /* offset at which the VM state can be saved (0 if not possible) */
 | 
					    /* offset at which the VM state can be saved (0 if not possible) */
 | 
				
			||||||
    int64_t vm_state_offset;
 | 
					    int64_t vm_state_offset;
 | 
				
			||||||
    bool is_dirty;
 | 
					 | 
				
			||||||
} BlockDriverInfo;
 | 
					} BlockDriverInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct BlockFragInfo {
 | 
					 | 
				
			||||||
    uint64_t allocated_clusters;
 | 
					 | 
				
			||||||
    uint64_t total_clusters;
 | 
					 | 
				
			||||||
    uint64_t fragmented_clusters;
 | 
					 | 
				
			||||||
} BlockFragInfo;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct QEMUSnapshotInfo {
 | 
					typedef struct QEMUSnapshotInfo {
 | 
				
			||||||
    char id_str[128]; /* unique snapshot id */
 | 
					    char id_str[128]; /* unique snapshot id */
 | 
				
			||||||
    /* the following fields are informative. They are not needed for
 | 
					    /* the following fields are informative. They are not needed for
 | 
				
			||||||
       the consistency of the snapshot */
 | 
					       the consistency of the snapshot */
 | 
				
			||||||
    char name[256]; /* user chosen name */
 | 
					    char name[256]; /* user choosen name */
 | 
				
			||||||
    uint64_t vm_state_size; /* VM state info size */
 | 
					    uint32_t vm_state_size; /* VM state info size */
 | 
				
			||||||
    uint32_t date_sec; /* UTC date of the snapshot */
 | 
					    uint32_t date_sec; /* UTC date of the snapshot */
 | 
				
			||||||
    uint32_t date_nsec;
 | 
					    uint32_t date_nsec;
 | 
				
			||||||
    uint64_t vm_clock_nsec; /* VM clock relative to boot */
 | 
					    uint64_t vm_clock_nsec; /* VM clock relative to boot */
 | 
				
			||||||
} QEMUSnapshotInfo;
 | 
					} QEMUSnapshotInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Callbacks for block device models */
 | 
					#define BDRV_O_RDONLY      0x0000
 | 
				
			||||||
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_RDWR        0x0002
 | 
					#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_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_NOCACHE     0x0020 /* do not use the host page cache */
 | 
				
			||||||
#define BDRV_O_CACHE_WB    0x0040 /* use write-back caching */
 | 
					#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_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_CHECK       0x1000  /* open solely for consistency check */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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_BITS   9
 | 
				
			||||||
#define BDRV_SECTOR_SIZE   (1ULL << BDRV_SECTOR_BITS)
 | 
					#define BDRV_SECTOR_SIZE   (1 << BDRV_SECTOR_BITS)
 | 
				
			||||||
#define BDRV_SECTOR_MASK   ~(BDRV_SECTOR_SIZE - 1)
 | 
					#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_print(Monitor *mon, const QObject *data);
 | 
				
			||||||
void bdrv_info(Monitor *mon, QObject **ret_data);
 | 
					void bdrv_info(Monitor *mon, QObject **ret_data);
 | 
				
			||||||
void bdrv_stats_print(Monitor *mon, const QObject *data);
 | 
					void bdrv_stats_print(Monitor *mon, const QObject *data);
 | 
				
			||||||
void bdrv_info_stats(Monitor *mon, QObject **ret_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(void);
 | 
				
			||||||
void bdrv_init_with_whitelist(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_format(const char *format_name);
 | 
				
			||||||
BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
 | 
					BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
 | 
				
			||||||
int bdrv_create(BlockDriver *drv, const char* filename,
 | 
					int bdrv_create(BlockDriver *drv, const char* filename,
 | 
				
			||||||
    QEMUOptionParameter *options);
 | 
					    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);
 | 
					BlockDriverState *bdrv_new(const char *device_name);
 | 
				
			||||||
void bdrv_make_anon(BlockDriverState *bs);
 | 
					 | 
				
			||||||
void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
 | 
					 | 
				
			||||||
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
 | 
					 | 
				
			||||||
void bdrv_delete(BlockDriverState *bs);
 | 
					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_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);
 | 
				
			||||||
              BlockDriver *drv);
 | 
					int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
 | 
				
			||||||
 | 
					               BlockDriver *drv);
 | 
				
			||||||
void bdrv_close(BlockDriverState *bs);
 | 
					void bdrv_close(BlockDriverState *bs);
 | 
				
			||||||
int bdrv_attach_dev(BlockDriverState *bs, void *dev);
 | 
					int bdrv_check(BlockDriverState *bs);
 | 
				
			||||||
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_read(BlockDriverState *bs, int64_t sector_num,
 | 
					int bdrv_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
              uint8_t *buf, int nb_sectors);
 | 
					              uint8_t *buf, int nb_sectors);
 | 
				
			||||||
int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
 | 
					 | 
				
			||||||
                          uint8_t *buf, int nb_sectors);
 | 
					 | 
				
			||||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
 | 
					int bdrv_write(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
               const uint8_t *buf, int nb_sectors);
 | 
					               const uint8_t *buf, int nb_sectors);
 | 
				
			||||||
int bdrv_pread(BlockDriverState *bs, int64_t offset,
 | 
					int bdrv_pread(BlockDriverState *bs, int64_t offset,
 | 
				
			||||||
@@ -153,59 +79,20 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
 | 
				
			|||||||
                const void *buf, int count);
 | 
					                const void *buf, int count);
 | 
				
			||||||
int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
 | 
					int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
 | 
				
			||||||
    const void *buf, int count);
 | 
					    const void *buf, int count);
 | 
				
			||||||
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
 | 
					int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
    int nb_sectors, QEMUIOVector *qiov);
 | 
					    const uint8_t *buf, int nb_sectors);
 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
 | 
					 | 
				
			||||||
                                            BlockDriverState *base,
 | 
					 | 
				
			||||||
                                            int64_t sector_num,
 | 
					 | 
				
			||||||
                                            int nb_sectors, int *pnum);
 | 
					 | 
				
			||||||
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
 | 
					 | 
				
			||||||
    const char *backing_file);
 | 
					 | 
				
			||||||
int bdrv_get_backing_file_depth(BlockDriverState *bs);
 | 
					 | 
				
			||||||
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 | 
					int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 | 
				
			||||||
int64_t bdrv_getlength(BlockDriverState *bs);
 | 
					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_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(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);
 | 
					void bdrv_register(BlockDriver *bdrv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct BdrvCheckResult {
 | 
					 | 
				
			||||||
    int corruptions;
 | 
					 | 
				
			||||||
    int leaks;
 | 
					 | 
				
			||||||
    int check_errors;
 | 
					 | 
				
			||||||
    int corruptions_fixed;
 | 
					 | 
				
			||||||
    int leaks_fixed;
 | 
					 | 
				
			||||||
    BlockFragInfo bfi;
 | 
					 | 
				
			||||||
} BdrvCheckResult;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum {
 | 
					 | 
				
			||||||
    BDRV_FIX_LEAKS    = 1,
 | 
					 | 
				
			||||||
    BDRV_FIX_ERRORS   = 2,
 | 
					 | 
				
			||||||
} BdrvCheckMode;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* async block I/O */
 | 
					/* async block I/O */
 | 
				
			||||||
 | 
					typedef struct BlockDriverAIOCB BlockDriverAIOCB;
 | 
				
			||||||
 | 
					typedef void BlockDriverCompletionFunc(void *opaque, int ret);
 | 
				
			||||||
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
 | 
					typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
 | 
				
			||||||
                                     int sector_num);
 | 
									     int sector_num);
 | 
				
			||||||
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
 | 
					BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
                                 QEMUIOVector *iov, int nb_sectors,
 | 
					                                 QEMUIOVector *iov, int nb_sectors,
 | 
				
			||||||
                                 BlockDriverCompletionFunc *cb, void *opaque);
 | 
					                                 BlockDriverCompletionFunc *cb, void *opaque);
 | 
				
			||||||
@@ -213,10 +100,7 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
                                  QEMUIOVector *iov, int nb_sectors,
 | 
					                                  QEMUIOVector *iov, int nb_sectors,
 | 
				
			||||||
                                  BlockDriverCompletionFunc *cb, void *opaque);
 | 
					                                  BlockDriverCompletionFunc *cb, void *opaque);
 | 
				
			||||||
BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
 | 
					BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
 | 
				
			||||||
                                 BlockDriverCompletionFunc *cb, void *opaque);
 | 
									 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);
 | 
					void bdrv_aio_cancel(BlockDriverAIOCB *acb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct BlockRequest {
 | 
					typedef struct BlockRequest {
 | 
				
			||||||
@@ -240,39 +124,44 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
 | 
				
			|||||||
        unsigned long int req, void *buf,
 | 
					        unsigned long int req, void *buf,
 | 
				
			||||||
        BlockDriverCompletionFunc *cb, void *opaque);
 | 
					        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.  */
 | 
					/* Ensure contents are flushed to disk.  */
 | 
				
			||||||
int bdrv_flush(BlockDriverState *bs);
 | 
					void bdrv_flush(BlockDriverState *bs);
 | 
				
			||||||
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
 | 
					 | 
				
			||||||
void bdrv_flush_all(void);
 | 
					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 bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
 | 
				
			||||||
                      int *pnum);
 | 
						int *pnum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
 | 
					#define BDRV_TYPE_HD     0
 | 
				
			||||||
                       BlockErrorAction on_write_error);
 | 
					#define BDRV_TYPE_CDROM  1
 | 
				
			||||||
BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
 | 
					#define BDRV_TYPE_FLOPPY 2
 | 
				
			||||||
 | 
					#define BIOS_ATA_TRANSLATION_AUTO   0
 | 
				
			||||||
 | 
					#define BIOS_ATA_TRANSLATION_NONE   1
 | 
				
			||||||
 | 
					#define BIOS_ATA_TRANSLATION_LBA    2
 | 
				
			||||||
 | 
					#define BIOS_ATA_TRANSLATION_LARGE  3
 | 
				
			||||||
 | 
					#define BIOS_ATA_TRANSLATION_RECHS  4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					int bdrv_get_type_hint(BlockDriverState *bs);
 | 
				
			||||||
 | 
					int bdrv_get_translation_hint(BlockDriverState *bs);
 | 
				
			||||||
 | 
					int bdrv_is_removable(BlockDriverState *bs);
 | 
				
			||||||
int bdrv_is_read_only(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_is_sg(BlockDriverState *bs);
 | 
				
			||||||
int bdrv_enable_write_cache(BlockDriverState *bs);
 | 
					int bdrv_enable_write_cache(BlockDriverState *bs);
 | 
				
			||||||
void bdrv_set_enable_write_cache(BlockDriverState *bs, bool wce);
 | 
					 | 
				
			||||||
int bdrv_is_inserted(BlockDriverState *bs);
 | 
					int bdrv_is_inserted(BlockDriverState *bs);
 | 
				
			||||||
int bdrv_media_changed(BlockDriverState *bs);
 | 
					int bdrv_media_changed(BlockDriverState *bs);
 | 
				
			||||||
void bdrv_lock_medium(BlockDriverState *bs, bool locked);
 | 
					int bdrv_is_locked(BlockDriverState *bs);
 | 
				
			||||||
void bdrv_eject(BlockDriverState *bs, bool eject_flag);
 | 
					void bdrv_set_locked(BlockDriverState *bs, int locked);
 | 
				
			||||||
const char *bdrv_get_format_name(BlockDriverState *bs);
 | 
					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_find(const char *name);
 | 
				
			||||||
BlockDriverState *bdrv_next(BlockDriverState *bs);
 | 
					 | 
				
			||||||
void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs),
 | 
					void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs),
 | 
				
			||||||
                  void *opaque);
 | 
					                  void *opaque);
 | 
				
			||||||
int bdrv_is_encrypted(BlockDriverState *bs);
 | 
					int bdrv_is_encrypted(BlockDriverState *bs);
 | 
				
			||||||
@@ -282,7 +171,6 @@ int bdrv_query_missing_keys(void);
 | 
				
			|||||||
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
 | 
					void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
 | 
				
			||||||
                         void *opaque);
 | 
					                         void *opaque);
 | 
				
			||||||
const char *bdrv_get_device_name(BlockDriverState *bs);
 | 
					const char *bdrv_get_device_name(BlockDriverState *bs);
 | 
				
			||||||
int bdrv_get_flags(BlockDriverState *bs);
 | 
					 | 
				
			||||||
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
 | 
					int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
                          const uint8_t *buf, int nb_sectors);
 | 
					                          const uint8_t *buf, int nb_sectors);
 | 
				
			||||||
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
 | 
					int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
 | 
				
			||||||
@@ -290,11 +178,6 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
 | 
				
			|||||||
const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
 | 
					const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
 | 
				
			||||||
void bdrv_get_backing_filename(BlockDriverState *bs,
 | 
					void bdrv_get_backing_filename(BlockDriverState *bs,
 | 
				
			||||||
                               char *filename, int filename_size);
 | 
					                               char *filename, int filename_size);
 | 
				
			||||||
void bdrv_get_full_backing_filename(BlockDriverState *bs,
 | 
					 | 
				
			||||||
                                    char *dest, size_t sz);
 | 
					 | 
				
			||||||
int bdrv_can_snapshot(BlockDriverState *bs);
 | 
					 | 
				
			||||||
int bdrv_is_snapshot(BlockDriverState *bs);
 | 
					 | 
				
			||||||
BlockDriverState *bdrv_snapshots(void);
 | 
					 | 
				
			||||||
int bdrv_snapshot_create(BlockDriverState *bs,
 | 
					int bdrv_snapshot_create(BlockDriverState *bs,
 | 
				
			||||||
                         QEMUSnapshotInfo *sn_info);
 | 
					                         QEMUSnapshotInfo *sn_info);
 | 
				
			||||||
int bdrv_snapshot_goto(BlockDriverState *bs,
 | 
					int bdrv_snapshot_goto(BlockDriverState *bs,
 | 
				
			||||||
@@ -302,8 +185,6 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
 | 
				
			|||||||
int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
 | 
					int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
 | 
				
			||||||
int bdrv_snapshot_list(BlockDriverState *bs,
 | 
					int bdrv_snapshot_list(BlockDriverState *bs,
 | 
				
			||||||
                       QEMUSnapshotInfo **psn_info);
 | 
					                       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 *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *get_human_readable_size(char *buf, int buf_size, int64_t size);
 | 
					char *get_human_readable_size(char *buf, int buf_size, int64_t size);
 | 
				
			||||||
@@ -318,91 +199,10 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
 | 
				
			|||||||
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
 | 
					int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
 | 
				
			||||||
                      int64_t pos, int size);
 | 
					                      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
 | 
					#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
 | 
					void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
 | 
				
			||||||
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
 | 
					int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
 | 
				
			||||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
 | 
					void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
 | 
				
			||||||
                      int nr_sectors);
 | 
					                      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_AIO,
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 | 
					 | 
				
			||||||
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
 | 
					 | 
				
			||||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
 | 
					 | 
				
			||||||
block-obj-y += qed-check.o
 | 
					 | 
				
			||||||
block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 | 
					 | 
				
			||||||
block-obj-y += stream.o
 | 
					 | 
				
			||||||
block-obj-$(CONFIG_WIN32) += raw-win32.o
 | 
					 | 
				
			||||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
 | 
					 | 
				
			||||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
 | 
					 | 
				
			||||||
block-obj-$(CONFIG_CURL) += curl.o
 | 
					 | 
				
			||||||
block-obj-$(CONFIG_RBD) += rbd.o
 | 
					 | 
				
			||||||
							
								
								
									
										473
									
								
								block/blkdebug.c
									
									
									
									
									
								
							
							
						
						
									
										473
									
								
								block/blkdebug.c
									
									
									
									
									
								
							@@ -1,473 +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 BDRVBlkdebugState {
 | 
					 | 
				
			||||||
    int state;
 | 
					 | 
				
			||||||
    QLIST_HEAD(, BlkdebugRule) rules[BLKDBG_EVENT_MAX];
 | 
					 | 
				
			||||||
    QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
 | 
					 | 
				
			||||||
} 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;
 | 
					 | 
				
			||||||
            int64_t sector;
 | 
					 | 
				
			||||||
        } inject;
 | 
					 | 
				
			||||||
        struct {
 | 
					 | 
				
			||||||
            int new_state;
 | 
					 | 
				
			||||||
        } set_state;
 | 
					 | 
				
			||||||
    } options;
 | 
					 | 
				
			||||||
    QLIST_ENTRY(BlkdebugRule) next;
 | 
					 | 
				
			||||||
    QSIMPLEQ_ENTRY(BlkdebugRule) active_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 = "sector",
 | 
					 | 
				
			||||||
            .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_AIO]                       = "read_aio",
 | 
					 | 
				
			||||||
    [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);
 | 
					 | 
				
			||||||
        rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
 | 
					 | 
				
			||||||
        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->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, BlkdebugRule *rule)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
					 | 
				
			||||||
    int error = rule->options.inject.error;
 | 
					 | 
				
			||||||
    struct BlkdebugAIOCB *acb;
 | 
					 | 
				
			||||||
    QEMUBH *bh;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (rule->options.inject.once) {
 | 
					 | 
				
			||||||
        QSIMPLEQ_INIT(&s->active_rules);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (rule->options.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;
 | 
					 | 
				
			||||||
    BlkdebugRule *rule = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
 | 
					 | 
				
			||||||
        if (rule->options.inject.sector == -1 ||
 | 
					 | 
				
			||||||
            (rule->options.inject.sector >= sector_num &&
 | 
					 | 
				
			||||||
             rule->options.inject.sector < sector_num + nb_sectors)) {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (rule && rule->options.inject.error) {
 | 
					 | 
				
			||||||
        return inject_error(bs, cb, opaque, rule);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
 | 
					 | 
				
			||||||
    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 | 
					 | 
				
			||||||
    BlockDriverCompletionFunc *cb, void *opaque)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
					 | 
				
			||||||
    BlkdebugRule *rule = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
 | 
					 | 
				
			||||||
        if (rule->options.inject.sector == -1 ||
 | 
					 | 
				
			||||||
            (rule->options.inject.sector >= sector_num &&
 | 
					 | 
				
			||||||
             rule->options.inject.sector < sector_num + nb_sectors)) {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (rule && rule->options.inject.error) {
 | 
					 | 
				
			||||||
        return inject_error(bs, cb, opaque, rule);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
 | 
					 | 
				
			||||||
    int old_state, bool injected)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Only process rules for the current state */
 | 
					 | 
				
			||||||
    if (rule->state && rule->state != old_state) {
 | 
					 | 
				
			||||||
        return injected;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Take the action */
 | 
					 | 
				
			||||||
    switch (rule->action) {
 | 
					 | 
				
			||||||
    case ACTION_INJECT_ERROR:
 | 
					 | 
				
			||||||
        if (!injected) {
 | 
					 | 
				
			||||||
            QSIMPLEQ_INIT(&s->active_rules);
 | 
					 | 
				
			||||||
            injected = true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case ACTION_SET_STATE:
 | 
					 | 
				
			||||||
        s->state = rule->options.set_state.new_state;
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return injected;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void blkdebug_debug_event(BlockDriverState *bs, BlkDebugEvent event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    BDRVBlkdebugState *s = bs->opaque;
 | 
					 | 
				
			||||||
    struct BlkdebugRule *rule;
 | 
					 | 
				
			||||||
    int old_state = s->state;
 | 
					 | 
				
			||||||
    bool injected;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert((int)event >= 0 && event < BLKDBG_EVENT_MAX);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    injected = false;
 | 
					 | 
				
			||||||
    QLIST_FOREACH(rule, &s->rules[event], next) {
 | 
					 | 
				
			||||||
        injected = process_rule(bs, rule, old_state, injected);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int64_t blkdebug_getlength(BlockDriverState *bs)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return bdrv_getlength(bs->file);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static BlockDriver bdrv_blkdebug = {
 | 
					 | 
				
			||||||
    .format_name        = "blkdebug",
 | 
					 | 
				
			||||||
    .protocol_name      = "blkdebug",
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .instance_size      = sizeof(BDRVBlkdebugState),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .bdrv_file_open     = blkdebug_open,
 | 
					 | 
				
			||||||
    .bdrv_close         = blkdebug_close,
 | 
					 | 
				
			||||||
    .bdrv_getlength     = blkdebug_getlength,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .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 {
 | 
					typedef struct BDRVBochsState {
 | 
				
			||||||
    CoMutex lock;
 | 
					    int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t *catalog_bitmap;
 | 
					    uint32_t *catalog_bitmap;
 | 
				
			||||||
    int catalog_size;
 | 
					    int catalog_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -108,16 +109,25 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
				
			|||||||
    return 0;
 | 
					    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;
 | 
					    BDRVBochsState *s = bs->opaque;
 | 
				
			||||||
    int i;
 | 
					    int fd, i;
 | 
				
			||||||
    struct bochs_header bochs;
 | 
					    struct bochs_header bochs;
 | 
				
			||||||
    struct bochs_header_v1 header_v1;
 | 
					    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
 | 
					    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;
 | 
					        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;
 | 
					      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_size = le32_to_cpu(bochs.extra.redolog.catalog);
 | 
				
			||||||
    s->catalog_bitmap = g_malloc(s->catalog_size * 4);
 | 
					    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
 | 
				
			||||||
    if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
 | 
					    if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
 | 
				
			||||||
                   s->catalog_size * 4) != s->catalog_size * 4)
 | 
						s->catalog_size * 4)
 | 
				
			||||||
	goto fail;
 | 
						goto fail;
 | 
				
			||||||
    for (i = 0; i < s->catalog_size; i++)
 | 
					    for (i = 0; i < s->catalog_size; i++)
 | 
				
			||||||
	le32_to_cpus(&s->catalog_bitmap[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);
 | 
					    s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_co_mutex_init(&s->lock);
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 fail:
 | 
					 fail:
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
    return -1;
 | 
					    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;
 | 
					    BDRVBochsState *s = bs->opaque;
 | 
				
			||||||
    int64_t offset = sector_num * 512;
 | 
					    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;
 | 
					    char bitmap_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // seek to sector
 | 
					    // seek to sector
 | 
				
			||||||
    extent_index = offset / s->extent_size;
 | 
					    extent_index = offset / s->extent_size;
 | 
				
			||||||
    extent_offset = (offset % s->extent_size) / 512;
 | 
					    extent_offset = (offset % s->extent_size) / 512;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->catalog_bitmap[extent_index] == 0xffffffff) {
 | 
					    if (s->catalog_bitmap[extent_index] == 0xffffffff)
 | 
				
			||||||
	return -1; /* not allocated */
 | 
					    {
 | 
				
			||||||
 | 
					//	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] *
 | 
					    bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
 | 
				
			||||||
	(s->extent_blocks + s->bitmap_blocks));
 | 
						(s->extent_blocks + s->bitmap_blocks));
 | 
				
			||||||
 | 
					    block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* read in bitmap for current extent */
 | 
					//    fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
 | 
				
			||||||
    if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
 | 
					//	sector_num, extent_index, extent_offset,
 | 
				
			||||||
                   &bitmap_entry, 1) != 1) {
 | 
					//	le32_to_cpu(s->catalog_bitmap[extent_index]),
 | 
				
			||||||
        return -1;
 | 
					//	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)) {
 | 
					    lseek(s->fd, block_offset, SEEK_SET);
 | 
				
			||||||
	return -1; /* not allocated */
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
 | 
					static int bochs_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
                    uint8_t *buf, int nb_sectors)
 | 
					                    uint8_t *buf, int nb_sectors)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    BDRVBochsState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (nb_sectors > 0) {
 | 
					    while (nb_sectors > 0) {
 | 
				
			||||||
        int64_t block_offset = seek_to_sector(bs, sector_num);
 | 
						if (!seek_to_sector(bs, sector_num))
 | 
				
			||||||
        if (block_offset >= 0) {
 | 
						{
 | 
				
			||||||
            ret = bdrv_pread(bs->file, block_offset, buf, 512);
 | 
						    ret = read(s->fd, buf, 512);
 | 
				
			||||||
            if (ret != 512) {
 | 
						    if (ret != 512)
 | 
				
			||||||
                return -1;
 | 
							return -1;
 | 
				
			||||||
            }
 | 
						}
 | 
				
			||||||
        } else
 | 
						else
 | 
				
			||||||
            memset(buf, 0, 512);
 | 
					            memset(buf, 0, 512);
 | 
				
			||||||
        nb_sectors--;
 | 
					        nb_sectors--;
 | 
				
			||||||
        sector_num++;
 | 
					        sector_num++;
 | 
				
			||||||
@@ -209,21 +235,11 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
    return 0;
 | 
					    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)
 | 
					static void bochs_close(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVBochsState *s = bs->opaque;
 | 
					    BDRVBochsState *s = bs->opaque;
 | 
				
			||||||
    g_free(s->catalog_bitmap);
 | 
					    qemu_free(s->catalog_bitmap);
 | 
				
			||||||
 | 
					    close(s->fd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriver bdrv_bochs = {
 | 
					static BlockDriver bdrv_bochs = {
 | 
				
			||||||
@@ -231,7 +247,7 @@ static BlockDriver bdrv_bochs = {
 | 
				
			|||||||
    .instance_size	= sizeof(BDRVBochsState),
 | 
					    .instance_size	= sizeof(BDRVBochsState),
 | 
				
			||||||
    .bdrv_probe		= bochs_probe,
 | 
					    .bdrv_probe		= bochs_probe,
 | 
				
			||||||
    .bdrv_open		= bochs_open,
 | 
					    .bdrv_open		= bochs_open,
 | 
				
			||||||
    .bdrv_read          = bochs_co_read,
 | 
					    .bdrv_read		= bochs_read,
 | 
				
			||||||
    .bdrv_close		= bochs_close,
 | 
					    .bdrv_close		= bochs_close,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										176
									
								
								block/cloop.c
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								block/cloop.c
									
									
									
									
									
								
							@@ -27,10 +27,10 @@
 | 
				
			|||||||
#include <zlib.h>
 | 
					#include <zlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct BDRVCloopState {
 | 
					typedef struct BDRVCloopState {
 | 
				
			||||||
    CoMutex lock;
 | 
					    int fd;
 | 
				
			||||||
    uint32_t block_size;
 | 
					    uint32_t block_size;
 | 
				
			||||||
    uint32_t n_blocks;
 | 
					    uint32_t n_blocks;
 | 
				
			||||||
    uint64_t *offsets;
 | 
					    uint64_t* offsets;
 | 
				
			||||||
    uint32_t sectors_per_block;
 | 
					    uint32_t sectors_per_block;
 | 
				
			||||||
    uint32_t current_block;
 | 
					    uint32_t current_block;
 | 
				
			||||||
    uint8_t *compressed_block;
 | 
					    uint8_t *compressed_block;
 | 
				
			||||||
@@ -40,99 +40,89 @@ typedef struct BDRVCloopState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
					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"
 | 
						"#V2.0 Format\n"
 | 
				
			||||||
        "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
 | 
						"modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
 | 
				
			||||||
    int length = strlen(magic_version_2_0);
 | 
					    int length=strlen(magic_version_2_0);
 | 
				
			||||||
    if (length > buf_size) {
 | 
					    if(length>buf_size)
 | 
				
			||||||
        length = buf_size;
 | 
						length=buf_size;
 | 
				
			||||||
    }
 | 
					    if(!memcmp(magic_version_2_0,buf,length))
 | 
				
			||||||
    if (!memcmp(magic_version_2_0, buf, length)) {
 | 
						return 2;
 | 
				
			||||||
        return 2;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					    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;
 | 
					    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;
 | 
					    bs->read_only = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* read header */
 | 
					    /* read header */
 | 
				
			||||||
    if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) {
 | 
					    if(lseek(s->fd,128,SEEK_SET)<0) {
 | 
				
			||||||
        goto cloop_close;
 | 
					cloop_close:
 | 
				
			||||||
 | 
						close(s->fd);
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    s->block_size = be32_to_cpu(s->block_size);
 | 
					    if(read(s->fd,&s->block_size,4)<4)
 | 
				
			||||||
 | 
						goto cloop_close;
 | 
				
			||||||
    if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) {
 | 
					    s->block_size=be32_to_cpu(s->block_size);
 | 
				
			||||||
        goto cloop_close;
 | 
					    if(read(s->fd,&s->n_blocks,4)<4)
 | 
				
			||||||
    }
 | 
						goto cloop_close;
 | 
				
			||||||
    s->n_blocks = be32_to_cpu(s->n_blocks);
 | 
					    s->n_blocks=be32_to_cpu(s->n_blocks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* read offsets */
 | 
					    /* read offsets */
 | 
				
			||||||
    offsets_size = s->n_blocks * sizeof(uint64_t);
 | 
					    offsets_size=s->n_blocks*sizeof(uint64_t);
 | 
				
			||||||
    s->offsets = g_malloc(offsets_size);
 | 
					    s->offsets=(uint64_t*)qemu_malloc(offsets_size);
 | 
				
			||||||
    if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
 | 
					    if(read(s->fd,s->offsets,offsets_size)<offsets_size)
 | 
				
			||||||
            offsets_size) {
 | 
						goto cloop_close;
 | 
				
			||||||
        goto cloop_close;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for(i=0;i<s->n_blocks;i++) {
 | 
					    for(i=0;i<s->n_blocks;i++) {
 | 
				
			||||||
        s->offsets[i] = be64_to_cpu(s->offsets[i]);
 | 
						s->offsets[i]=be64_to_cpu(s->offsets[i]);
 | 
				
			||||||
        if (i > 0) {
 | 
						if(i>0) {
 | 
				
			||||||
            uint32_t size = s->offsets[i] - s->offsets[i - 1];
 | 
						    uint32_t size=s->offsets[i]-s->offsets[i-1];
 | 
				
			||||||
            if (size > max_compressed_block_size) {
 | 
						    if(size>max_compressed_block_size)
 | 
				
			||||||
                max_compressed_block_size = size;
 | 
							max_compressed_block_size=size;
 | 
				
			||||||
            }
 | 
						}
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* initialize zlib engine */
 | 
					    /* initialize zlib engine */
 | 
				
			||||||
    s->compressed_block = g_malloc(max_compressed_block_size + 1);
 | 
					    s->compressed_block = qemu_malloc(max_compressed_block_size+1);
 | 
				
			||||||
    s->uncompressed_block = g_malloc(s->block_size);
 | 
					    s->uncompressed_block = qemu_malloc(s->block_size);
 | 
				
			||||||
    if (inflateInit(&s->zstream) != Z_OK) {
 | 
					    if(inflateInit(&s->zstream) != Z_OK)
 | 
				
			||||||
        goto cloop_close;
 | 
						goto cloop_close;
 | 
				
			||||||
    }
 | 
					    s->current_block=s->n_blocks;
 | 
				
			||||||
    s->current_block = s->n_blocks;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->sectors_per_block = s->block_size/512;
 | 
					    s->sectors_per_block = s->block_size/512;
 | 
				
			||||||
    bs->total_sectors = s->n_blocks * s->sectors_per_block;
 | 
					    bs->total_sectors = s->n_blocks*s->sectors_per_block;
 | 
				
			||||||
    qemu_co_mutex_init(&s->lock);
 | 
					 | 
				
			||||||
    return 0;
 | 
					    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) {
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					        uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->current_block != block_num) {
 | 
						lseek(s->fd, s->offsets[block_num], SEEK_SET);
 | 
				
			||||||
        int ret;
 | 
					        ret = read(s->fd, s->compressed_block, bytes);
 | 
				
			||||||
        uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
 | 
					        if (ret != bytes)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
 | 
					 | 
				
			||||||
                         bytes);
 | 
					 | 
				
			||||||
        if (ret != bytes) {
 | 
					 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        s->zstream.next_in = s->compressed_block;
 | 
						s->zstream.next_in = s->compressed_block;
 | 
				
			||||||
        s->zstream.avail_in = bytes;
 | 
						s->zstream.avail_in = bytes;
 | 
				
			||||||
        s->zstream.next_out = s->uncompressed_block;
 | 
						s->zstream.next_out = s->uncompressed_block;
 | 
				
			||||||
        s->zstream.avail_out = s->block_size;
 | 
						s->zstream.avail_out = s->block_size;
 | 
				
			||||||
        ret = inflateReset(&s->zstream);
 | 
						ret = inflateReset(&s->zstream);
 | 
				
			||||||
        if (ret != Z_OK) {
 | 
						if(ret != Z_OK)
 | 
				
			||||||
            return -1;
 | 
						    return -1;
 | 
				
			||||||
        }
 | 
						ret = inflate(&s->zstream, Z_FINISH);
 | 
				
			||||||
        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;
 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        s->current_block = block_num;
 | 
						s->current_block = block_num;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -143,48 +133,34 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
    BDRVCloopState *s = bs->opaque;
 | 
					    BDRVCloopState *s = bs->opaque;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < nb_sectors; i++) {
 | 
					    for(i=0;i<nb_sectors;i++) {
 | 
				
			||||||
        uint32_t sector_offset_in_block =
 | 
						uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
 | 
				
			||||||
            ((sector_num + i) % s->sectors_per_block),
 | 
						    block_num=(sector_num+i)/s->sectors_per_block;
 | 
				
			||||||
            block_num = (sector_num + i) / s->sectors_per_block;
 | 
						if(cloop_read_block(s, block_num) != 0)
 | 
				
			||||||
        if (cloop_read_block(bs, block_num) != 0) {
 | 
						    return -1;
 | 
				
			||||||
            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;
 | 
					    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)
 | 
					static void cloop_close(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVCloopState *s = bs->opaque;
 | 
					    BDRVCloopState *s = bs->opaque;
 | 
				
			||||||
    if (s->n_blocks > 0) {
 | 
					    close(s->fd);
 | 
				
			||||||
        g_free(s->offsets);
 | 
					    if(s->n_blocks>0)
 | 
				
			||||||
    }
 | 
						free(s->offsets);
 | 
				
			||||||
    g_free(s->compressed_block);
 | 
					    free(s->compressed_block);
 | 
				
			||||||
    g_free(s->uncompressed_block);
 | 
					    free(s->uncompressed_block);
 | 
				
			||||||
    inflateEnd(&s->zstream);
 | 
					    inflateEnd(&s->zstream);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriver bdrv_cloop = {
 | 
					static BlockDriver bdrv_cloop = {
 | 
				
			||||||
    .format_name    = "cloop",
 | 
					    .format_name	= "cloop",
 | 
				
			||||||
    .instance_size  = sizeof(BDRVCloopState),
 | 
					    .instance_size	= sizeof(BDRVCloopState),
 | 
				
			||||||
    .bdrv_probe     = cloop_probe,
 | 
					    .bdrv_probe		= cloop_probe,
 | 
				
			||||||
    .bdrv_open      = cloop_open,
 | 
					    .bdrv_open		= cloop_open,
 | 
				
			||||||
    .bdrv_read      = cloop_co_read,
 | 
					    .bdrv_read		= cloop_read,
 | 
				
			||||||
    .bdrv_close     = cloop_close,
 | 
					    .bdrv_close		= cloop_close,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void bdrv_cloop_init(void)
 | 
					static void bdrv_cloop_init(void)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										257
									
								
								block/cow.c
									
									
									
									
									
								
							
							
						
						
									
										257
									
								
								block/cow.c
									
									
									
									
									
								
							@@ -21,9 +21,11 @@
 | 
				
			|||||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
				
			||||||
 * THE SOFTWARE.
 | 
					 * THE SOFTWARE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef _WIN32
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
#include "block_int.h"
 | 
					#include "block_int.h"
 | 
				
			||||||
#include "module.h"
 | 
					#include "module.h"
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**************************************************************/
 | 
					/**************************************************************/
 | 
				
			||||||
/* COW block driver using file system holes */
 | 
					/* COW block driver using file system holes */
 | 
				
			||||||
@@ -42,7 +44,10 @@ struct cow_header_v2 {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct BDRVCowState {
 | 
					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;
 | 
					    int64_t cow_sectors_offset;
 | 
				
			||||||
} BDRVCowState;
 | 
					} BDRVCowState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -58,32 +63,27 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
 | 
				
			|||||||
        return 0;
 | 
					        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;
 | 
					    BDRVCowState *s = bs->opaque;
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
    struct cow_header_v2 cow_header;
 | 
					    struct cow_header_v2 cow_header;
 | 
				
			||||||
    int bitmap_size;
 | 
					 | 
				
			||||||
    int64_t 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 */
 | 
					    /* see if it is a cow image */
 | 
				
			||||||
    ret = bdrv_pread(bs->file, 0, &cow_header, sizeof(cow_header));
 | 
					    if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (be32_to_cpu(cow_header.magic) != COW_MAGIC) {
 | 
					    if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
 | 
				
			||||||
        ret = -EINVAL;
 | 
					        be32_to_cpu(cow_header.version) != COW_VERSION) {
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,118 +94,84 @@ static int cow_open(BlockDriverState *bs, int flags)
 | 
				
			|||||||
    pstrcpy(bs->backing_file, sizeof(bs->backing_file),
 | 
					    pstrcpy(bs->backing_file, sizeof(bs->backing_file),
 | 
				
			||||||
            cow_header.backing_file);
 | 
					            cow_header.backing_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
 | 
					    /* mmap the bitmap */
 | 
				
			||||||
    s->cow_sectors_offset = (bitmap_size + 511) & ~511;
 | 
					    s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
 | 
				
			||||||
    qemu_co_mutex_init(&s->lock);
 | 
					    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;
 | 
					    return 0;
 | 
				
			||||||
 fail:
 | 
					 fail:
 | 
				
			||||||
    return ret;
 | 
					    close(fd);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
 | 
				
			||||||
 * 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)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
 | 
					    bitmap[bitnum / 8] |= (1 << (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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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;
 | 
					    return !!(bitmap[bitnum / 8] & (1 << (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 true if first block has been changed (ie. current version is
 | 
					/* Return true if first block has been changed (ie. current version is
 | 
				
			||||||
 * in COW file).  Set the number of continuous blocks for which that
 | 
					 * in COW file).  Set the number of continuous blocks for which that
 | 
				
			||||||
 * is true. */
 | 
					 * is true. */
 | 
				
			||||||
static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs,
 | 
					static inline int is_changed(uint8_t *bitmap,
 | 
				
			||||||
        int64_t sector_num, int nb_sectors, int *num_same)
 | 
					                             int64_t sector_num, int nb_sectors,
 | 
				
			||||||
 | 
					                             int *num_same)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int changed;
 | 
					    int changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nb_sectors == 0) {
 | 
					    if (!bitmap || nb_sectors == 0) {
 | 
				
			||||||
	*num_same = nb_sectors;
 | 
						*num_same = nb_sectors;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    changed = is_bit_set(bs, sector_num);
 | 
					    changed = is_bit_set(bitmap, sector_num);
 | 
				
			||||||
    if (changed < 0) {
 | 
					 | 
				
			||||||
        return 0; /* XXX: how to return I/O errors? */
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
 | 
					    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;
 | 
						    break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return changed;
 | 
					    return changed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
 | 
					static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
        int nb_sectors)
 | 
					                            int nb_sectors, int *pnum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int error = 0;
 | 
					    BDRVCowState *s = bs->opaque;
 | 
				
			||||||
    int i;
 | 
					    return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < nb_sectors; i++) {
 | 
					 | 
				
			||||||
        error = cow_set_bit(bs, sector_num + i);
 | 
					 | 
				
			||||||
        if (error) {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return error;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
					                    uint8_t *buf, int nb_sectors)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVCowState *s = bs->opaque;
 | 
					    BDRVCowState *s = bs->opaque;
 | 
				
			||||||
    int ret, n;
 | 
					    int ret, n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (nb_sectors > 0) {
 | 
					    while (nb_sectors > 0) {
 | 
				
			||||||
        if (bdrv_co_is_allocated(bs, sector_num, nb_sectors, &n)) {
 | 
					        if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
 | 
				
			||||||
            ret = bdrv_pread(bs->file,
 | 
					            lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
 | 
				
			||||||
                        s->cow_sectors_offset + sector_num * 512,
 | 
					            ret = read(s->fd, buf, n * 512);
 | 
				
			||||||
                        buf, n * 512);
 | 
					            if (ret != n * 512)
 | 
				
			||||||
            if (ret < 0) {
 | 
					                return -1;
 | 
				
			||||||
                return ret;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if (bs->backing_hd) {
 | 
					            if (bs->backing_hd) {
 | 
				
			||||||
                /* read from the base image */
 | 
					                /* read from the base image */
 | 
				
			||||||
                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
 | 
					                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
 | 
				
			||||||
                if (ret < 0) {
 | 
					                if (ret < 0)
 | 
				
			||||||
                    return ret;
 | 
					                    return -1;
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                memset(buf, 0, n * 512);
 | 
					            memset(buf, 0, n * 512);
 | 
				
			||||||
            }
 | 
					        }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        nb_sectors -= n;
 | 
					        nb_sectors -= n;
 | 
				
			||||||
        sector_num += n;
 | 
					        sector_num += n;
 | 
				
			||||||
@@ -214,55 +180,35 @@ static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
    return 0;
 | 
					    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,
 | 
					static int cow_write(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
                     const uint8_t *buf, int nb_sectors)
 | 
					                     const uint8_t *buf, int nb_sectors)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVCowState *s = bs->opaque;
 | 
					    BDRVCowState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    int ret, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_pwrite(bs->file, s->cow_sectors_offset + sector_num * 512,
 | 
					    lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
 | 
				
			||||||
                      buf, nb_sectors * 512);
 | 
					    ret = write(s->fd, buf, nb_sectors * 512);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret != nb_sectors * 512)
 | 
				
			||||||
        return ret;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    for (i = 0; i < nb_sectors; i++)
 | 
				
			||||||
 | 
					        cow_set_bit(s->cow_bitmap, sector_num + i);
 | 
				
			||||||
    return cow_update_bitmap(bs, sector_num, nb_sectors);
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cow_close(BlockDriverState *bs)
 | 
					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)
 | 
					static int cow_create(const char *filename, QEMUOptionParameter *options)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    int fd, cow_fd;
 | 
				
			||||||
    struct cow_header_v2 cow_header;
 | 
					    struct cow_header_v2 cow_header;
 | 
				
			||||||
    struct stat st;
 | 
					    struct stat st;
 | 
				
			||||||
    int64_t image_sectors = 0;
 | 
					    int64_t image_sectors = 0;
 | 
				
			||||||
    const char *image_filename = NULL;
 | 
					    const char *image_filename = NULL;
 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
    BlockDriverState *cow_bs;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Read out options */
 | 
					    /* Read out options */
 | 
				
			||||||
    while (options && options->name) {
 | 
					    while (options && options->name) {
 | 
				
			||||||
@@ -274,16 +220,10 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
 | 
				
			|||||||
        options++;
 | 
					        options++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_create_file(filename, options);
 | 
					    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
 | 
				
			||||||
    if (ret < 0) {
 | 
					              0644);
 | 
				
			||||||
        return ret;
 | 
					    if (cow_fd < 0)
 | 
				
			||||||
    }
 | 
					        return -1;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret = bdrv_file_open(&cow_bs, filename, BDRV_O_RDWR);
 | 
					 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memset(&cow_header, 0, sizeof(cow_header));
 | 
					    memset(&cow_header, 0, sizeof(cow_header));
 | 
				
			||||||
    cow_header.magic = cpu_to_be32(COW_MAGIC);
 | 
					    cow_header.magic = cpu_to_be32(COW_MAGIC);
 | 
				
			||||||
    cow_header.version = cpu_to_be32(COW_VERSION);
 | 
					    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 */
 | 
					        /* Note: if no file, we put a dummy mtime */
 | 
				
			||||||
        cow_header.mtime = cpu_to_be32(0);
 | 
					        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;
 | 
					            goto mtime_fail;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (fstat(fd, &st) != 0) {
 | 
				
			||||||
 | 
					            close(fd);
 | 
				
			||||||
 | 
					            goto mtime_fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        close(fd);
 | 
				
			||||||
        cow_header.mtime = cpu_to_be32(st.st_mtime);
 | 
					        cow_header.mtime = cpu_to_be32(st.st_mtime);
 | 
				
			||||||
    mtime_fail:
 | 
					    mtime_fail:
 | 
				
			||||||
        pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
 | 
					        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.sectorsize = cpu_to_be32(512);
 | 
				
			||||||
    cow_header.size = cpu_to_be64(image_sectors * 512);
 | 
					    cow_header.size = cpu_to_be64(image_sectors * 512);
 | 
				
			||||||
    ret = bdrv_pwrite(cow_bs, 0, &cow_header, sizeof(cow_header));
 | 
					    write(cow_fd, &cow_header, sizeof(cow_header));
 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        goto exit;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* resize to include at least all the bitmap */
 | 
					    /* resize to include at least all the bitmap */
 | 
				
			||||||
    ret = bdrv_truncate(cow_bs,
 | 
					    ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
 | 
				
			||||||
        sizeof(cow_header) + ((image_sectors + 7) >> 3));
 | 
					    close(cow_fd);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    return 0;
 | 
				
			||||||
        goto exit;
 | 
					}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit:
 | 
					static void cow_flush(BlockDriverState *bs)
 | 
				
			||||||
    bdrv_delete(cow_bs);
 | 
					{
 | 
				
			||||||
    return ret;
 | 
					    BDRVCowState *s = bs->opaque;
 | 
				
			||||||
 | 
					    qemu_fdatasync(s->fd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static QEMUOptionParameter cow_create_options[] = {
 | 
					static QEMUOptionParameter cow_create_options[] = {
 | 
				
			||||||
@@ -333,17 +276,16 @@ static QEMUOptionParameter cow_create_options[] = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriver bdrv_cow = {
 | 
					static BlockDriver bdrv_cow = {
 | 
				
			||||||
    .format_name    = "cow",
 | 
					    .format_name	= "cow",
 | 
				
			||||||
    .instance_size  = sizeof(BDRVCowState),
 | 
					    .instance_size	= sizeof(BDRVCowState),
 | 
				
			||||||
 | 
					    .bdrv_probe		= cow_probe,
 | 
				
			||||||
    .bdrv_probe     = cow_probe,
 | 
					    .bdrv_open		= cow_open,
 | 
				
			||||||
    .bdrv_open      = cow_open,
 | 
					    .bdrv_read		= cow_read,
 | 
				
			||||||
    .bdrv_close     = cow_close,
 | 
					    .bdrv_write		= cow_write,
 | 
				
			||||||
    .bdrv_create    = cow_create,
 | 
					    .bdrv_close		= cow_close,
 | 
				
			||||||
 | 
					    .bdrv_create	= cow_create,
 | 
				
			||||||
    .bdrv_read              = cow_co_read,
 | 
					    .bdrv_flush		= cow_flush,
 | 
				
			||||||
    .bdrv_write             = cow_co_write,
 | 
					    .bdrv_is_allocated	= cow_is_allocated,
 | 
				
			||||||
    .bdrv_co_is_allocated   = cow_co_is_allocated,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .create_options = cow_create_options,
 | 
					    .create_options = cow_create_options,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -354,3 +296,4 @@ static void bdrv_cow_init(void)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block_init(bdrv_cow_init);
 | 
					block_init(bdrv_cow_init);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										162
									
								
								block/curl.c
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								block/curl.c
									
									
									
									
									
								
							@@ -29,9 +29,9 @@
 | 
				
			|||||||
// #define DEBUG_VERBOSE
 | 
					// #define DEBUG_VERBOSE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG_CURL
 | 
					#ifdef DEBUG_CURL
 | 
				
			||||||
#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
 | 
					#define dprintf(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define DPRINTF(fmt, ...) do { } while (0)
 | 
					#define dprintf(fmt, ...) do { } while (0)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CURL_NUM_STATES 8
 | 
					#define CURL_NUM_STATES 8
 | 
				
			||||||
@@ -47,12 +47,7 @@ struct BDRVCURLState;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
typedef struct CURLAIOCB {
 | 
					typedef struct CURLAIOCB {
 | 
				
			||||||
    BlockDriverAIOCB common;
 | 
					    BlockDriverAIOCB common;
 | 
				
			||||||
    QEMUBH *bh;
 | 
					 | 
				
			||||||
    QEMUIOVector *qiov;
 | 
					    QEMUIOVector *qiov;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    int64_t sector_num;
 | 
					 | 
				
			||||||
    int nb_sectors;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    size_t start;
 | 
					    size_t start;
 | 
				
			||||||
    size_t end;
 | 
					    size_t end;
 | 
				
			||||||
} CURLAIOCB;
 | 
					} CURLAIOCB;
 | 
				
			||||||
@@ -81,25 +76,24 @@ typedef struct BDRVCURLState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void curl_clean_state(CURLState *s);
 | 
					static void curl_clean_state(CURLState *s);
 | 
				
			||||||
static void curl_multi_do(void *arg);
 | 
					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,
 | 
					static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
 | 
				
			||||||
                        void *s, void *sp)
 | 
					                        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) {
 | 
					    switch (action) {
 | 
				
			||||||
        case CURL_POLL_IN:
 | 
					        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;
 | 
					            break;
 | 
				
			||||||
        case CURL_POLL_OUT:
 | 
					        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;
 | 
					            break;
 | 
				
			||||||
        case CURL_POLL_INOUT:
 | 
					        case CURL_POLL_INOUT:
 | 
				
			||||||
            qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
 | 
					            qemu_aio_set_fd_handler(fd, curl_multi_do,
 | 
				
			||||||
                                    curl_aio_flush, s);
 | 
					                                    curl_multi_do, NULL, NULL, s);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case CURL_POLL_REMOVE:
 | 
					        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;
 | 
					            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);
 | 
					    CURLState *s = ((CURLState*)opaque);
 | 
				
			||||||
    size_t realsize = size * nmemb;
 | 
					    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;
 | 
					        s->s->len = fsize;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return realsize;
 | 
					    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;
 | 
					    size_t realsize = size * nmemb;
 | 
				
			||||||
    int i;
 | 
					    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)
 | 
					    if (!s || !s->orig_buf)
 | 
				
			||||||
        goto read_end;
 | 
					        goto read_end;
 | 
				
			||||||
@@ -140,8 +133,8 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
 | 
				
			|||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ((s->buf_off >= acb->end)) {
 | 
					        if ((s->buf_off >= acb->end)) {
 | 
				
			||||||
            qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
 | 
					            qemu_iovec_from_buffer(acb->qiov, s->orig_buf + acb->start,
 | 
				
			||||||
                                acb->end - acb->start);
 | 
					                                   acb->end - acb->start);
 | 
				
			||||||
            acb->common.cb(acb->common.opaque, 0);
 | 
					            acb->common.cb(acb->common.opaque, 0);
 | 
				
			||||||
            qemu_aio_release(acb);
 | 
					            qemu_aio_release(acb);
 | 
				
			||||||
            s->acb[i] = NULL;
 | 
					            s->acb[i] = NULL;
 | 
				
			||||||
@@ -176,7 +169,7 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            char *buf = state->orig_buf + (start - state->buf_start);
 | 
					            char *buf = state->orig_buf + (start - state->buf_start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            qemu_iovec_from_buf(acb->qiov, 0, buf, len);
 | 
					            qemu_iovec_from_buffer(acb->qiov, buf, len);
 | 
				
			||||||
            acb->common.cb(acb->common.opaque, 0);
 | 
					            acb->common.cb(acb->common.opaque, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return FIND_RET_OK;
 | 
					            return FIND_RET_OK;
 | 
				
			||||||
@@ -235,23 +228,6 @@ static void curl_multi_do(void *arg)
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                CURLState *state = NULL;
 | 
					                CURLState *state = NULL;
 | 
				
			||||||
                curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
 | 
					                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);
 | 
					                curl_clean_state(state);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -280,7 +256,7 @@ static CURLState *curl_init_state(BDRVCURLState *s)
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (!state) {
 | 
					        if (!state) {
 | 
				
			||||||
            g_usleep(100);
 | 
					            usleep(100);
 | 
				
			||||||
            curl_multi_do(s);
 | 
					            curl_multi_do(s);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } while(!state);
 | 
					    } while(!state);
 | 
				
			||||||
@@ -300,8 +276,7 @@ static CURLState *curl_init_state(BDRVCURLState *s)
 | 
				
			|||||||
    curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
 | 
					    curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
 | 
				
			||||||
    curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
 | 
					    curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
 | 
				
			||||||
    curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
 | 
					    curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
 | 
				
			||||||
    curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
 | 
					    
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef DEBUG_VERBOSE
 | 
					#ifdef DEBUG_VERBOSE
 | 
				
			||||||
    curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
 | 
					    curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -334,7 +309,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    static int inited = 0;
 | 
					    static int inited = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    file = g_strdup(filename);
 | 
					    file = qemu_strdup(filename);
 | 
				
			||||||
    s->readahead_size = READ_AHEAD_SIZE;
 | 
					    s->readahead_size = READ_AHEAD_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Parse a trailing ":readahead=#:" param, if present. */
 | 
					    /* 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) {
 | 
					    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);
 | 
					                s->readahead_size);
 | 
				
			||||||
        goto out_noclean;
 | 
					        goto out_noclean;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -374,7 +349,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
 | 
				
			|||||||
        inited = 1;
 | 
					        inited = 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("CURL: Opening %s\n", file);
 | 
					    dprintf("CURL: Opening %s\n", file);
 | 
				
			||||||
    s->url = file;
 | 
					    s->url = file;
 | 
				
			||||||
    state = curl_init_state(s);
 | 
					    state = curl_init_state(s);
 | 
				
			||||||
    if (!state)
 | 
					    if (!state)
 | 
				
			||||||
@@ -393,7 +368,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
 | 
				
			|||||||
        s->len = (size_t)d;
 | 
					        s->len = (size_t)d;
 | 
				
			||||||
    else if(!s->len)
 | 
					    else if(!s->len)
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    DPRINTF("CURL: Size = %zd\n", s->len);
 | 
					    dprintf("CURL: Size = %lld\n", (long long)s->len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    curl_clean_state(state);
 | 
					    curl_clean_state(state);
 | 
				
			||||||
    curl_easy_cleanup(state->curl);
 | 
					    curl_easy_cleanup(state->curl);
 | 
				
			||||||
@@ -414,25 +389,10 @@ out:
 | 
				
			|||||||
    curl_easy_cleanup(state->curl);
 | 
					    curl_easy_cleanup(state->curl);
 | 
				
			||||||
    state->curl = NULL;
 | 
					    state->curl = NULL;
 | 
				
			||||||
out_noclean:
 | 
					out_noclean:
 | 
				
			||||||
    g_free(file);
 | 
					    qemu_free(file);
 | 
				
			||||||
    return -EINVAL;
 | 
					    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)
 | 
					static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Do we have to implement canceling? Seems to work without...
 | 
					    // Do we have to implement canceling? Seems to work without...
 | 
				
			||||||
@@ -443,82 +403,60 @@ static AIOPool curl_aio_pool = {
 | 
				
			|||||||
    .cancel             = curl_aio_cancel,
 | 
					    .cancel             = curl_aio_cancel,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
 | 
				
			||||||
static void curl_readv_bh_cb(void *p)
 | 
					        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;
 | 
					    CURLState *state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CURLAIOCB *acb = p;
 | 
					    acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
 | 
				
			||||||
    BDRVCURLState *s = acb->common.bs->opaque;
 | 
					    if (!acb)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_bh_delete(acb->bh);
 | 
					    acb->qiov = qiov;
 | 
				
			||||||
    acb->bh = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    size_t start = acb->sector_num * SECTOR_SIZE;
 | 
					 | 
				
			||||||
    size_t end;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // In case we have the requested data already (e.g. read-ahead),
 | 
					    // In case we have the requested data already (e.g. read-ahead),
 | 
				
			||||||
    // we can just call the callback and be done.
 | 
					    // 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:
 | 
					        case FIND_RET_OK:
 | 
				
			||||||
            qemu_aio_release(acb);
 | 
					            qemu_aio_release(acb);
 | 
				
			||||||
            // fall through
 | 
					            // fall through
 | 
				
			||||||
        case FIND_RET_WAIT:
 | 
					        case FIND_RET_WAIT:
 | 
				
			||||||
            return;
 | 
					            return &acb->common;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // No cache found, so let's start a new request
 | 
					    // No cache found, so let's start a new request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = curl_init_state(s);
 | 
					    state = curl_init_state(s);
 | 
				
			||||||
    if (!state) {
 | 
					    if (!state)
 | 
				
			||||||
        acb->common.cb(acb->common.opaque, -EIO);
 | 
					        return NULL;
 | 
				
			||||||
        qemu_aio_release(acb);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    acb->start = 0;
 | 
					    acb->start = 0;
 | 
				
			||||||
    acb->end = (acb->nb_sectors * SECTOR_SIZE);
 | 
					    acb->end = (nb_sectors * SECTOR_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state->buf_off = 0;
 | 
					    state->buf_off = 0;
 | 
				
			||||||
    if (state->orig_buf)
 | 
					    if (state->orig_buf)
 | 
				
			||||||
        g_free(state->orig_buf);
 | 
					        qemu_free(state->orig_buf);
 | 
				
			||||||
    state->buf_start = start;
 | 
					    state->buf_start = start;
 | 
				
			||||||
    state->buf_len = acb->end + s->readahead_size;
 | 
					    state->buf_len = acb->end + s->readahead_size;
 | 
				
			||||||
    end = MIN(start + state->buf_len, s->len) - 1;
 | 
					    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;
 | 
					    state->acb[0] = acb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    snprintf(state->range, 127, "%zd-%zd", start, end);
 | 
					    snprintf(state->range, 127, "%lld-%lld", (long long)start, (long long)end);
 | 
				
			||||||
    DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
 | 
					    dprintf("CURL (AIO): Reading %d at %lld (%s)\n", (nb_sectors * SECTOR_SIZE), start, state->range);
 | 
				
			||||||
            (acb->nb_sectors * SECTOR_SIZE), start, state->range);
 | 
					 | 
				
			||||||
    curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
 | 
					    curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    curl_multi_add_handle(s->multi, state->curl);
 | 
					    curl_multi_add_handle(s->multi, state->curl);
 | 
				
			||||||
    curl_multi_do(s);
 | 
					    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;
 | 
					    return &acb->common;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -527,7 +465,7 @@ static void curl_close(BlockDriverState *bs)
 | 
				
			|||||||
    BDRVCURLState *s = bs->opaque;
 | 
					    BDRVCURLState *s = bs->opaque;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("CURL: Close\n");
 | 
					    dprintf("CURL: Close\n");
 | 
				
			||||||
    for (i=0; i<CURL_NUM_STATES; i++) {
 | 
					    for (i=0; i<CURL_NUM_STATES; i++) {
 | 
				
			||||||
        if (s->states[i].in_use)
 | 
					        if (s->states[i].in_use)
 | 
				
			||||||
            curl_clean_state(&s->states[i]);
 | 
					            curl_clean_state(&s->states[i]);
 | 
				
			||||||
@@ -536,7 +474,7 @@ static void curl_close(BlockDriverState *bs)
 | 
				
			|||||||
            s->states[i].curl = NULL;
 | 
					            s->states[i].curl = NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (s->states[i].orig_buf) {
 | 
					        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;
 | 
					            s->states[i].orig_buf = NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -557,7 +495,7 @@ static BlockDriver bdrv_http = {
 | 
				
			|||||||
    .protocol_name   = "http",
 | 
					    .protocol_name   = "http",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
					    .instance_size   = sizeof(BDRVCURLState),
 | 
				
			||||||
    .bdrv_file_open  = curl_open,
 | 
					    .bdrv_open       = curl_open,
 | 
				
			||||||
    .bdrv_close      = curl_close,
 | 
					    .bdrv_close      = curl_close,
 | 
				
			||||||
    .bdrv_getlength  = curl_getlength,
 | 
					    .bdrv_getlength  = curl_getlength,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -569,7 +507,7 @@ static BlockDriver bdrv_https = {
 | 
				
			|||||||
    .protocol_name   = "https",
 | 
					    .protocol_name   = "https",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
					    .instance_size   = sizeof(BDRVCURLState),
 | 
				
			||||||
    .bdrv_file_open  = curl_open,
 | 
					    .bdrv_open       = curl_open,
 | 
				
			||||||
    .bdrv_close      = curl_close,
 | 
					    .bdrv_close      = curl_close,
 | 
				
			||||||
    .bdrv_getlength  = curl_getlength,
 | 
					    .bdrv_getlength  = curl_getlength,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -581,7 +519,7 @@ static BlockDriver bdrv_ftp = {
 | 
				
			|||||||
    .protocol_name   = "ftp",
 | 
					    .protocol_name   = "ftp",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
					    .instance_size   = sizeof(BDRVCURLState),
 | 
				
			||||||
    .bdrv_file_open  = curl_open,
 | 
					    .bdrv_open       = curl_open,
 | 
				
			||||||
    .bdrv_close      = curl_close,
 | 
					    .bdrv_close      = curl_close,
 | 
				
			||||||
    .bdrv_getlength  = curl_getlength,
 | 
					    .bdrv_getlength  = curl_getlength,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -593,7 +531,7 @@ static BlockDriver bdrv_ftps = {
 | 
				
			|||||||
    .protocol_name   = "ftps",
 | 
					    .protocol_name   = "ftps",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
					    .instance_size   = sizeof(BDRVCURLState),
 | 
				
			||||||
    .bdrv_file_open  = curl_open,
 | 
					    .bdrv_open       = curl_open,
 | 
				
			||||||
    .bdrv_close      = curl_close,
 | 
					    .bdrv_close      = curl_close,
 | 
				
			||||||
    .bdrv_getlength  = curl_getlength,
 | 
					    .bdrv_getlength  = curl_getlength,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -605,7 +543,7 @@ static BlockDriver bdrv_tftp = {
 | 
				
			|||||||
    .protocol_name   = "tftp",
 | 
					    .protocol_name   = "tftp",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .instance_size   = sizeof(BDRVCURLState),
 | 
					    .instance_size   = sizeof(BDRVCURLState),
 | 
				
			||||||
    .bdrv_file_open  = curl_open,
 | 
					    .bdrv_open       = curl_open,
 | 
				
			||||||
    .bdrv_close      = curl_close,
 | 
					    .bdrv_close      = curl_close,
 | 
				
			||||||
    .bdrv_getlength  = curl_getlength,
 | 
					    .bdrv_getlength  = curl_getlength,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										136
									
								
								block/dmg.c
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								block/dmg.c
									
									
									
									
									
								
							@@ -28,7 +28,8 @@
 | 
				
			|||||||
#include <zlib.h>
 | 
					#include <zlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct BDRVDMGState {
 | 
					typedef struct BDRVDMGState {
 | 
				
			||||||
    CoMutex lock;
 | 
					    int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* each chunk contains a certain number of sectors,
 | 
					    /* each chunk contains a certain number of sectors,
 | 
				
			||||||
     * offsets[i] is the offset in the .dmg file,
 | 
					     * offsets[i] is the offset in the .dmg file,
 | 
				
			||||||
     * lengths[i] is the length of the compressed chunk,
 | 
					     * 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;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static off_t read_off(BlockDriverState *bs, int64_t offset)
 | 
					static off_t read_off(int fd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint64_t buffer;
 | 
						uint64_t buffer;
 | 
				
			||||||
	if (bdrv_pread(bs->file, offset, &buffer, 8) < 8)
 | 
						if(read(fd,&buffer,8)<8)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	return be64_to_cpu(buffer);
 | 
						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;
 | 
						uint32_t buffer;
 | 
				
			||||||
	if (bdrv_pread(bs->file, offset, &buffer, 4) < 4)
 | 
						if(read(fd,&buffer,4)<4)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	return be32_to_cpu(buffer);
 | 
						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;
 | 
					    BDRVDMGState *s = bs->opaque;
 | 
				
			||||||
    off_t info_begin,info_end,last_in_offset,last_out_offset;
 | 
					    off_t info_begin,info_end,last_in_offset,last_out_offset;
 | 
				
			||||||
    uint32_t count;
 | 
					    uint32_t count;
 | 
				
			||||||
    uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
 | 
					    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;
 | 
					    bs->read_only = 1;
 | 
				
			||||||
    s->n_chunks = 0;
 | 
					    s->n_chunks = 0;
 | 
				
			||||||
    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
 | 
					    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* read offset of info blocks */
 | 
					    /* read offset of info blocks */
 | 
				
			||||||
    offset = bdrv_getlength(bs->file);
 | 
					    if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
 | 
				
			||||||
    if (offset < 0) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    offset -= 0x1d8;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info_begin = read_off(bs, offset);
 | 
					    info_begin=read_off(s->fd);
 | 
				
			||||||
    if (info_begin == 0) {
 | 
					    if(info_begin==0)
 | 
				
			||||||
 | 
						goto fail;
 | 
				
			||||||
 | 
					    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;
 | 
						goto fail;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (read_uint32(bs, info_begin) != 0x100) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    count = read_uint32(bs, info_begin + 4);
 | 
					 | 
				
			||||||
    if (count == 0) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    info_end = info_begin + count;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    offset = info_begin + 0x100;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* read offsets */
 | 
					    /* read offsets */
 | 
				
			||||||
    last_in_offset = last_out_offset = 0;
 | 
					    last_in_offset = last_out_offset = 0;
 | 
				
			||||||
    while (offset < info_end) {
 | 
					    while(lseek(s->fd,0,SEEK_CUR)<info_end) {
 | 
				
			||||||
        uint32_t type;
 | 
					        uint32_t type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	count = read_uint32(bs, offset);
 | 
						count = read_uint32(s->fd);
 | 
				
			||||||
	if(count==0)
 | 
						if(count==0)
 | 
				
			||||||
	    goto fail;
 | 
						    goto fail;
 | 
				
			||||||
        offset += 4;
 | 
						type = read_uint32(s->fd);
 | 
				
			||||||
 | 
						if(type!=0x6d697368 || count<244)
 | 
				
			||||||
	type = read_uint32(bs, offset);
 | 
						    lseek(s->fd,count-4,SEEK_CUR);
 | 
				
			||||||
	if (type == 0x6d697368 && count >= 244) {
 | 
						else {
 | 
				
			||||||
	    int new_size, chunk_count;
 | 
						    int new_size, chunk_count;
 | 
				
			||||||
 | 
						    if(lseek(s->fd,200,SEEK_CUR)<0)
 | 
				
			||||||
            offset += 4;
 | 
						        goto fail;
 | 
				
			||||||
            offset += 200;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    chunk_count = (count-204)/40;
 | 
						    chunk_count = (count-204)/40;
 | 
				
			||||||
	    new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
 | 
						    new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
 | 
				
			||||||
	    s->types = g_realloc(s->types, new_size/2);
 | 
						    s->types = qemu_realloc(s->types, new_size/2);
 | 
				
			||||||
	    s->offsets = g_realloc(s->offsets, new_size);
 | 
						    s->offsets = qemu_realloc(s->offsets, new_size);
 | 
				
			||||||
	    s->lengths = g_realloc(s->lengths, new_size);
 | 
						    s->lengths = qemu_realloc(s->lengths, new_size);
 | 
				
			||||||
	    s->sectors = g_realloc(s->sectors, new_size);
 | 
						    s->sectors = qemu_realloc(s->sectors, new_size);
 | 
				
			||||||
	    s->sectorcounts = g_realloc(s->sectorcounts, new_size);
 | 
						    s->sectorcounts = qemu_realloc(s->sectorcounts, new_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
 | 
						    for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
 | 
				
			||||||
		s->types[i] = read_uint32(bs, offset);
 | 
							s->types[i] = read_uint32(s->fd);
 | 
				
			||||||
		offset += 4;
 | 
					 | 
				
			||||||
		if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
 | 
							if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
 | 
				
			||||||
		    if(s->types[i]==0xffffffff) {
 | 
							    if(s->types[i]==0xffffffff) {
 | 
				
			||||||
			last_in_offset = s->offsets[i-1]+s->lengths[i-1];
 | 
								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--;
 | 
							    chunk_count--;
 | 
				
			||||||
		    i--;
 | 
							    i--;
 | 
				
			||||||
		    offset += 36;
 | 
							    if(lseek(s->fd,36,SEEK_CUR)<0)
 | 
				
			||||||
 | 
								goto fail;
 | 
				
			||||||
		    continue;
 | 
							    continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		offset += 4;
 | 
							read_uint32(s->fd);
 | 
				
			||||||
 | 
							s->sectors[i] = last_out_offset+read_off(s->fd);
 | 
				
			||||||
		s->sectors[i] = last_out_offset+read_off(bs, offset);
 | 
							s->sectorcounts[i] = read_off(s->fd);
 | 
				
			||||||
		offset += 8;
 | 
							s->offsets[i] = last_in_offset+read_off(s->fd);
 | 
				
			||||||
 | 
							s->lengths[i] = read_off(s->fd);
 | 
				
			||||||
		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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(s->lengths[i]>max_compressed_size)
 | 
							if(s->lengths[i]>max_compressed_size)
 | 
				
			||||||
		    max_compressed_size = s->lengths[i];
 | 
							    max_compressed_size = s->lengths[i];
 | 
				
			||||||
		if(s->sectorcounts[i]>max_sectors_per_chunk)
 | 
							if(s->sectorcounts[i]>max_sectors_per_chunk)
 | 
				
			||||||
@@ -171,16 +157,16 @@ static int dmg_open(BlockDriverState *bs, int flags)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* initialize zlib engine */
 | 
					    /* initialize zlib engine */
 | 
				
			||||||
    s->compressed_chunk = g_malloc(max_compressed_size+1);
 | 
					    s->compressed_chunk = qemu_malloc(max_compressed_size+1);
 | 
				
			||||||
    s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
 | 
					    s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
 | 
				
			||||||
    if(inflateInit(&s->zstream) != Z_OK)
 | 
					    if(inflateInit(&s->zstream) != Z_OK)
 | 
				
			||||||
	goto fail;
 | 
						goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->current_chunk = s->n_chunks;
 | 
					    s->current_chunk = s->n_chunks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_co_mutex_init(&s->lock);
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
 | 
					    close(s->fd);
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -210,10 +196,8 @@ static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
 | 
				
			|||||||
    return s->n_chunks; /* error */
 | 
					    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)) {
 | 
					    if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	uint32_t chunk = search_chunk(s,sector_num);
 | 
						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 */
 | 
						case 0x80000005: { /* zlib compressed */
 | 
				
			||||||
	    int i;
 | 
						    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
 | 
						    /* we need to buffer, because only the chunk as whole can be
 | 
				
			||||||
	     * inflated. */
 | 
						     * inflated. */
 | 
				
			||||||
	    i=0;
 | 
						    i=0;
 | 
				
			||||||
	    do {
 | 
						    do {
 | 
				
			||||||
                ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
 | 
							ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i);
 | 
				
			||||||
                                 s->compressed_chunk+i, s->lengths[chunk]-i);
 | 
					 | 
				
			||||||
		if(ret<0 && errno==EINTR)
 | 
							if(ret<0 && errno==EINTR)
 | 
				
			||||||
		    ret=0;
 | 
							    ret=0;
 | 
				
			||||||
		i+=ret;
 | 
							i+=ret;
 | 
				
			||||||
@@ -252,8 +239,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
 | 
				
			|||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	    break; }
 | 
						    break; }
 | 
				
			||||||
	case 1: /* copy */
 | 
						case 1: /* copy */
 | 
				
			||||||
	    ret = bdrv_pread(bs->file, s->offsets[chunk],
 | 
						    ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]);
 | 
				
			||||||
                             s->uncompressed_chunk, s->lengths[chunk]);
 | 
					 | 
				
			||||||
	    if (ret != s->lengths[chunk])
 | 
						    if (ret != s->lengths[chunk])
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	    break;
 | 
						    break;
 | 
				
			||||||
@@ -274,7 +260,7 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    for(i=0;i<nb_sectors;i++) {
 | 
					    for(i=0;i<nb_sectors;i++) {
 | 
				
			||||||
	uint32_t sector_offset_in_chunk;
 | 
						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;
 | 
						    return -1;
 | 
				
			||||||
	sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
 | 
						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);
 | 
						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;
 | 
					    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)
 | 
					static void dmg_close(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVDMGState *s = bs->opaque;
 | 
					    BDRVDMGState *s = bs->opaque;
 | 
				
			||||||
 | 
					    close(s->fd);
 | 
				
			||||||
    if(s->n_chunks>0) {
 | 
					    if(s->n_chunks>0) {
 | 
				
			||||||
	free(s->types);
 | 
						free(s->types);
 | 
				
			||||||
	free(s->offsets);
 | 
						free(s->offsets);
 | 
				
			||||||
@@ -313,7 +289,7 @@ static BlockDriver bdrv_dmg = {
 | 
				
			|||||||
    .instance_size	= sizeof(BDRVDMGState),
 | 
					    .instance_size	= sizeof(BDRVDMGState),
 | 
				
			||||||
    .bdrv_probe		= dmg_probe,
 | 
					    .bdrv_probe		= dmg_probe,
 | 
				
			||||||
    .bdrv_open		= dmg_open,
 | 
					    .bdrv_open		= dmg_open,
 | 
				
			||||||
    .bdrv_read          = dmg_co_read,
 | 
					    .bdrv_read		= dmg_read,
 | 
				
			||||||
    .bdrv_close		= dmg_close,
 | 
					    .bdrv_close		= dmg_close,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1081
									
								
								block/iscsi.c
									
									
									
									
									
								
							
							
						
						
									
										1081
									
								
								block/iscsi.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										527
									
								
								block/nbd.c
									
									
									
									
									
								
							
							
						
						
									
										527
									
								
								block/nbd.c
									
									
									
									
									
								
							@@ -28,465 +28,146 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "qemu-common.h"
 | 
					#include "qemu-common.h"
 | 
				
			||||||
#include "nbd.h"
 | 
					#include "nbd.h"
 | 
				
			||||||
#include "block_int.h"
 | 
					 | 
				
			||||||
#include "module.h"
 | 
					#include "module.h"
 | 
				
			||||||
#include "qemu_socket.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <unistd.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 {
 | 
					typedef struct BDRVNBDState {
 | 
				
			||||||
    int sock;
 | 
					    int sock;
 | 
				
			||||||
    uint32_t nbdflags;
 | 
					 | 
				
			||||||
    off_t size;
 | 
					    off_t size;
 | 
				
			||||||
    size_t blocksize;
 | 
					    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;
 | 
					} BDRVNBDState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
 | 
					static int nbd_open(BlockDriverState *bs, 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,
 | 
					 | 
				
			||||||
                               QEMUIOVector *qiov, 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 && qiov) {
 | 
					 | 
				
			||||||
        ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
 | 
					 | 
				
			||||||
                            offset, request->len);
 | 
					 | 
				
			||||||
        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,
 | 
					 | 
				
			||||||
                                 QEMUIOVector *qiov, 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 (qiov && reply->error == 0) {
 | 
					 | 
				
			||||||
            ret = qemu_co_recvv(s->sock, qiov->iov, qiov->niov,
 | 
					 | 
				
			||||||
                                offset, request->len);
 | 
					 | 
				
			||||||
            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)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVNBDState *s = bs->opaque;
 | 
					    BDRVNBDState *s = bs->opaque;
 | 
				
			||||||
 | 
					    const char *host;
 | 
				
			||||||
 | 
					    const char *unixpath;
 | 
				
			||||||
    int sock;
 | 
					    int sock;
 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
    off_t size;
 | 
					    off_t size;
 | 
				
			||||||
    size_t blocksize;
 | 
					    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 {
 | 
					    } 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 == -1)
 | 
				
			||||||
    if (sock < 0) {
 | 
					 | 
				
			||||||
        logout("Failed to establish connection to NBD server\n");
 | 
					 | 
				
			||||||
        return -errno;
 | 
					        return -errno;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* NBD handshake */
 | 
					    ret = nbd_receive_negotiate(sock, &size, &blocksize);
 | 
				
			||||||
    ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size,
 | 
					    if (ret == -1)
 | 
				
			||||||
                                &blocksize);
 | 
					        return -errno;
 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->sock = sock;
 | 
					    s->sock = sock;
 | 
				
			||||||
    s->size = size;
 | 
					    s->size = size;
 | 
				
			||||||
    s->blocksize = blocksize;
 | 
					    s->blocksize = blocksize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logout("Established connection with NBD server\n");
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nbd_teardown_connection(BlockDriverState *bs)
 | 
					static int nbd_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
{
 | 
					                    uint8_t *buf, int nb_sectors)
 | 
				
			||||||
    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)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVNBDState *s = bs->opaque;
 | 
					    BDRVNBDState *s = bs->opaque;
 | 
				
			||||||
    struct nbd_request request;
 | 
					    struct nbd_request request;
 | 
				
			||||||
    struct nbd_reply reply;
 | 
					    struct nbd_reply reply;
 | 
				
			||||||
    ssize_t ret;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    request.type = NBD_CMD_READ;
 | 
					    request.type = NBD_CMD_READ;
 | 
				
			||||||
    request.from = sector_num * 512;
 | 
					    request.handle = (uint64_t)(intptr_t)bs;
 | 
				
			||||||
    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, 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, 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.from = sector_num * 512;;
 | 
					    request.from = sector_num * 512;;
 | 
				
			||||||
    request.len = nb_sectors * 512;
 | 
					    request.len = nb_sectors * 512;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nbd_coroutine_start(s, &request);
 | 
					    if (nbd_send_request(s->sock, &request) == -1)
 | 
				
			||||||
    ret = nbd_co_send_request(s, &request, NULL, 0);
 | 
					        return -errno;
 | 
				
			||||||
    if (ret < 0) {
 | 
					
 | 
				
			||||||
        reply.error = -ret;
 | 
					    if (nbd_receive_reply(s->sock, &reply) == -1)
 | 
				
			||||||
    } else {
 | 
					        return -errno;
 | 
				
			||||||
        nbd_co_receive_reply(s, &request, &reply, NULL, 0);
 | 
					
 | 
				
			||||||
    }
 | 
					    if (reply.error !=0)
 | 
				
			||||||
    nbd_coroutine_end(s, &request);
 | 
					        return -reply.error;
 | 
				
			||||||
    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)
 | 
					static void nbd_close(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVNBDState *s = bs->opaque;
 | 
					    BDRVNBDState *s = bs->opaque;
 | 
				
			||||||
    g_free(s->export_name);
 | 
					    struct nbd_request request;
 | 
				
			||||||
    g_free(s->host_spec);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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)
 | 
					static int64_t nbd_getlength(BlockDriverState *bs)
 | 
				
			||||||
@@ -497,16 +178,14 @@ static int64_t nbd_getlength(BlockDriverState *bs)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriver bdrv_nbd = {
 | 
					static BlockDriver bdrv_nbd = {
 | 
				
			||||||
    .format_name         = "nbd",
 | 
					    .format_name	= "nbd",
 | 
				
			||||||
    .instance_size       = sizeof(BDRVNBDState),
 | 
					    .instance_size	= sizeof(BDRVNBDState),
 | 
				
			||||||
    .bdrv_file_open      = nbd_open,
 | 
					    .bdrv_open		= nbd_open,
 | 
				
			||||||
    .bdrv_co_readv       = nbd_co_readv,
 | 
					    .bdrv_read		= nbd_read,
 | 
				
			||||||
    .bdrv_co_writev      = nbd_co_writev,
 | 
					    .bdrv_write		= nbd_write,
 | 
				
			||||||
    .bdrv_close          = nbd_close,
 | 
					    .bdrv_close		= nbd_close,
 | 
				
			||||||
    .bdrv_co_flush_to_os = nbd_co_flush,
 | 
					    .bdrv_getlength	= nbd_getlength,
 | 
				
			||||||
    .bdrv_co_discard     = nbd_co_discard,
 | 
					    .protocol_name	= "nbd",
 | 
				
			||||||
    .bdrv_getlength      = nbd_getlength,
 | 
					 | 
				
			||||||
    .protocol_name       = "nbd",
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void bdrv_nbd_init(void)
 | 
					static void bdrv_nbd_init(void)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,10 +43,10 @@ struct parallels_header {
 | 
				
			|||||||
    uint32_t catalog_entries;
 | 
					    uint32_t catalog_entries;
 | 
				
			||||||
    uint32_t nb_sectors;
 | 
					    uint32_t nb_sectors;
 | 
				
			||||||
    char padding[24];
 | 
					    char padding[24];
 | 
				
			||||||
} QEMU_PACKED;
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct BDRVParallelsState {
 | 
					typedef struct BDRVParallelsState {
 | 
				
			||||||
    CoMutex lock;
 | 
					    int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t *catalog_bitmap;
 | 
					    uint32_t *catalog_bitmap;
 | 
				
			||||||
    int catalog_size;
 | 
					    int catalog_size;
 | 
				
			||||||
@@ -68,15 +68,24 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
 | 
				
			|||||||
    return 0;
 | 
					    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;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
    int i;
 | 
					    int fd, i;
 | 
				
			||||||
    struct parallels_header ph;
 | 
					    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
 | 
					    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;
 | 
					        goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
 | 
					    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);
 | 
					    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->tracks = le32_to_cpu(ph.tracks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->catalog_size = le32_to_cpu(ph.catalog_entries);
 | 
					    s->catalog_size = le32_to_cpu(ph.catalog_entries);
 | 
				
			||||||
    s->catalog_bitmap = g_malloc(s->catalog_size * 4);
 | 
					    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
 | 
				
			||||||
    if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) !=
 | 
					    if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
 | 
				
			||||||
	s->catalog_size * 4)
 | 
						s->catalog_size * 4)
 | 
				
			||||||
	goto fail;
 | 
						goto fail;
 | 
				
			||||||
    for (i = 0; i < s->catalog_size; i++)
 | 
					    for (i = 0; i < s->catalog_size; i++)
 | 
				
			||||||
	le32_to_cpus(&s->catalog_bitmap[i]);
 | 
						le32_to_cpus(&s->catalog_bitmap[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_co_mutex_init(&s->lock);
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
    if (s->catalog_bitmap)
 | 
					    if (s->catalog_bitmap)
 | 
				
			||||||
	g_free(s->catalog_bitmap);
 | 
						qemu_free(s->catalog_bitmap);
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
    return -1;
 | 
					    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;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
    uint32_t index, offset;
 | 
					    uint32_t index, offset;
 | 
				
			||||||
 | 
					    uint64_t position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    index = sector_num / s->tracks;
 | 
					    index = sector_num / s->tracks;
 | 
				
			||||||
    offset = sector_num % s->tracks;
 | 
					    offset = sector_num % s->tracks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* not allocated */
 | 
					    // not allocated
 | 
				
			||||||
    if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
 | 
					    if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
 | 
				
			||||||
	return -1;
 | 
						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,
 | 
					static int parallels_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
                    uint8_t *buf, int nb_sectors)
 | 
					                    uint8_t *buf, int nb_sectors)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (nb_sectors > 0) {
 | 
					    while (nb_sectors > 0) {
 | 
				
			||||||
        int64_t position = seek_to_sector(bs, sector_num);
 | 
						if (!seek_to_sector(bs, sector_num)) {
 | 
				
			||||||
        if (position >= 0) {
 | 
						    if (read(s->fd, buf, 512) != 512)
 | 
				
			||||||
            if (bdrv_pread(bs->file, position, buf, 512) != 512)
 | 
							return -1;
 | 
				
			||||||
                return -1;
 | 
						} else
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            memset(buf, 0, 512);
 | 
					            memset(buf, 0, 512);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        nb_sectors--;
 | 
					        nb_sectors--;
 | 
				
			||||||
        sector_num++;
 | 
					        sector_num++;
 | 
				
			||||||
        buf += 512;
 | 
					        buf += 512;
 | 
				
			||||||
@@ -136,21 +158,11 @@ static int parallels_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
    return 0;
 | 
					    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)
 | 
					static void parallels_close(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVParallelsState *s = bs->opaque;
 | 
					    BDRVParallelsState *s = bs->opaque;
 | 
				
			||||||
    g_free(s->catalog_bitmap);
 | 
					    qemu_free(s->catalog_bitmap);
 | 
				
			||||||
 | 
					    close(s->fd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriver bdrv_parallels = {
 | 
					static BlockDriver bdrv_parallels = {
 | 
				
			||||||
@@ -158,7 +170,7 @@ static BlockDriver bdrv_parallels = {
 | 
				
			|||||||
    .instance_size	= sizeof(BDRVParallelsState),
 | 
					    .instance_size	= sizeof(BDRVParallelsState),
 | 
				
			||||||
    .bdrv_probe		= parallels_probe,
 | 
					    .bdrv_probe		= parallels_probe,
 | 
				
			||||||
    .bdrv_open		= parallels_open,
 | 
					    .bdrv_open		= parallels_open,
 | 
				
			||||||
    .bdrv_read          = parallels_co_read,
 | 
					    .bdrv_read		= parallels_read,
 | 
				
			||||||
    .bdrv_close		= parallels_close,
 | 
					    .bdrv_close		= parallels_close,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										660
									
								
								block/qcow.c
									
									
									
									
									
								
							
							
						
						
									
										660
									
								
								block/qcow.c
									
									
									
									
									
								
							@@ -26,7 +26,6 @@
 | 
				
			|||||||
#include "module.h"
 | 
					#include "module.h"
 | 
				
			||||||
#include <zlib.h>
 | 
					#include <zlib.h>
 | 
				
			||||||
#include "aes.h"
 | 
					#include "aes.h"
 | 
				
			||||||
#include "migration.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**************************************************************/
 | 
					/**************************************************************/
 | 
				
			||||||
/* QEMU COW block driver with compression and encryption support */
 | 
					/* QEMU COW block driver with compression and encryption support */
 | 
				
			||||||
@@ -55,6 +54,7 @@ typedef struct QCowHeader {
 | 
				
			|||||||
#define L2_CACHE_SIZE 16
 | 
					#define L2_CACHE_SIZE 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct BDRVQcowState {
 | 
					typedef struct BDRVQcowState {
 | 
				
			||||||
 | 
					    BlockDriverState *hd;
 | 
				
			||||||
    int cluster_bits;
 | 
					    int cluster_bits;
 | 
				
			||||||
    int cluster_size;
 | 
					    int cluster_size;
 | 
				
			||||||
    int cluster_sectors;
 | 
					    int cluster_sectors;
 | 
				
			||||||
@@ -74,11 +74,9 @@ typedef struct BDRVQcowState {
 | 
				
			|||||||
    uint32_t crypt_method_header;
 | 
					    uint32_t crypt_method_header;
 | 
				
			||||||
    AES_KEY aes_encrypt_key;
 | 
					    AES_KEY aes_encrypt_key;
 | 
				
			||||||
    AES_KEY aes_decrypt_key;
 | 
					    AES_KEY aes_decrypt_key;
 | 
				
			||||||
    CoMutex lock;
 | 
					 | 
				
			||||||
    Error *migration_blocker;
 | 
					 | 
				
			||||||
} BDRVQcowState;
 | 
					} 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)
 | 
					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;
 | 
					        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;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    int len, i, shift, ret;
 | 
					    int len, i, shift, ret;
 | 
				
			||||||
    QCowHeader header;
 | 
					    QCowHeader header;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
 | 
					    ret = bdrv_file_open(&s->hd, filename, flags);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0)
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    be32_to_cpus(&header.magic);
 | 
					    be32_to_cpus(&header.magic);
 | 
				
			||||||
    be32_to_cpus(&header.version);
 | 
					    be32_to_cpus(&header.version);
 | 
				
			||||||
    be64_to_cpus(&header.backing_file_offset);
 | 
					    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);
 | 
					    be32_to_cpus(&header.crypt_method);
 | 
				
			||||||
    be64_to_cpus(&header.l1_table_offset);
 | 
					    be64_to_cpus(&header.l1_table_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (header.magic != QCOW_MAGIC) {
 | 
					    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
 | 
				
			||||||
        ret = -EINVAL;
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    if (header.size <= 1 || header.cluster_bits < 9)
 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    if (header.crypt_method > QCOW_CRYPT_AES)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (header.size <= 1 || header.cluster_bits < 9) {
 | 
					 | 
				
			||||||
        ret = -EINVAL;
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (header.crypt_method > QCOW_CRYPT_AES) {
 | 
					 | 
				
			||||||
        ret = -EINVAL;
 | 
					 | 
				
			||||||
        goto fail;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    s->crypt_method_header = header.crypt_method;
 | 
					    s->crypt_method_header = header.crypt_method;
 | 
				
			||||||
    if (s->crypt_method_header) {
 | 
					    if (s->crypt_method_header)
 | 
				
			||||||
        bs->encrypted = 1;
 | 
					        bs->encrypted = 1;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    s->cluster_bits = header.cluster_bits;
 | 
					    s->cluster_bits = header.cluster_bits;
 | 
				
			||||||
    s->cluster_size = 1 << s->cluster_bits;
 | 
					    s->cluster_size = 1 << s->cluster_bits;
 | 
				
			||||||
    s->cluster_sectors = 1 << (s->cluster_bits - 9);
 | 
					    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_size = (header.size + (1LL << shift) - 1) >> shift;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->l1_table_offset = header.l1_table_offset;
 | 
					    s->l1_table_offset = header.l1_table_offset;
 | 
				
			||||||
    s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
 | 
					    s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
 | 
				
			||||||
 | 
					    if (!s->l1_table)
 | 
				
			||||||
    ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
 | 
					        goto fail;
 | 
				
			||||||
               s->l1_size * sizeof(uint64_t));
 | 
					    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
 | 
				
			||||||
    if (ret < 0) {
 | 
					        s->l1_size * sizeof(uint64_t))
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(i = 0;i < s->l1_size; i++) {
 | 
					    for(i = 0;i < s->l1_size; i++) {
 | 
				
			||||||
        be64_to_cpus(&s->l1_table[i]);
 | 
					        be64_to_cpus(&s->l1_table[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /* alloc L2 cache */
 | 
					    /* alloc L2 cache */
 | 
				
			||||||
    s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
 | 
					    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
 | 
				
			||||||
    s->cluster_cache = g_malloc(s->cluster_size);
 | 
					    if (!s->l2_cache)
 | 
				
			||||||
    s->cluster_data = g_malloc(s->cluster_size);
 | 
					        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;
 | 
					    s->cluster_cache_offset = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* read the backing file name */
 | 
					    /* read the backing file name */
 | 
				
			||||||
    if (header.backing_file_offset != 0) {
 | 
					    if (header.backing_file_offset != 0) {
 | 
				
			||||||
        len = header.backing_file_size;
 | 
					        len = header.backing_file_size;
 | 
				
			||||||
        if (len > 1023) {
 | 
					        if (len > 1023)
 | 
				
			||||||
            len = 1023;
 | 
					            len = 1023;
 | 
				
			||||||
        }
 | 
					        if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
 | 
				
			||||||
        ret = bdrv_pread(bs->file, header.backing_file_offset,
 | 
					 | 
				
			||||||
                   bs->backing_file, len);
 | 
					 | 
				
			||||||
        if (ret < 0) {
 | 
					 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        bs->backing_file[len] = '\0';
 | 
					        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;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail:
 | 
					 fail:
 | 
				
			||||||
    g_free(s->l1_table);
 | 
					    qemu_free(s->l1_table);
 | 
				
			||||||
    g_free(s->l2_cache);
 | 
					    qemu_free(s->l2_cache);
 | 
				
			||||||
    g_free(s->cluster_cache);
 | 
					    qemu_free(s->cluster_cache);
 | 
				
			||||||
    g_free(s->cluster_data);
 | 
					    qemu_free(s->cluster_data);
 | 
				
			||||||
    return ret;
 | 
					    bdrv_delete(s->hd);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qcow_set_key(BlockDriverState *bs, const char *key)
 | 
					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;
 | 
					        return -1;
 | 
				
			||||||
    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
 | 
					    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
 | 
				
			||||||
        return -1;
 | 
					        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;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -277,13 +271,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
				
			|||||||
        if (!allocate)
 | 
					        if (!allocate)
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        /* allocate a new l2 entry */
 | 
					        /* allocate a new l2 entry */
 | 
				
			||||||
        l2_offset = bdrv_getlength(bs->file);
 | 
					        l2_offset = bdrv_getlength(s->hd);
 | 
				
			||||||
        /* round to cluster size */
 | 
					        /* round to cluster size */
 | 
				
			||||||
        l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
 | 
					        l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
 | 
				
			||||||
        /* update the L1 entry */
 | 
					        /* update the L1 entry */
 | 
				
			||||||
        s->l1_table[l1_index] = l2_offset;
 | 
					        s->l1_table[l1_index] = l2_offset;
 | 
				
			||||||
        tmp = cpu_to_be64(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),
 | 
					                s->l1_table_offset + l1_index * sizeof(tmp),
 | 
				
			||||||
                &tmp, sizeof(tmp)) < 0)
 | 
					                &tmp, sizeof(tmp)) < 0)
 | 
				
			||||||
            return 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);
 | 
					    l2_table = s->l2_cache + (min_index << s->l2_bits);
 | 
				
			||||||
    if (new_l2_table) {
 | 
					    if (new_l2_table) {
 | 
				
			||||||
        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
 | 
					        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)
 | 
					                s->l2_size * sizeof(uint64_t)) < 0)
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
    } else {
 | 
					    } 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))
 | 
					            s->l2_size * sizeof(uint64_t))
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -336,22 +330,22 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
				
			|||||||
            /* if the cluster is already compressed, we must
 | 
					            /* if the cluster is already compressed, we must
 | 
				
			||||||
               decompress it in the case it is not completely
 | 
					               decompress it in the case it is not completely
 | 
				
			||||||
               overwritten */
 | 
					               overwritten */
 | 
				
			||||||
            if (decompress_cluster(bs, cluster_offset) < 0)
 | 
					            if (decompress_cluster(s, cluster_offset) < 0)
 | 
				
			||||||
                return 0;
 | 
					                return 0;
 | 
				
			||||||
            cluster_offset = bdrv_getlength(bs->file);
 | 
					            cluster_offset = bdrv_getlength(s->hd);
 | 
				
			||||||
            cluster_offset = (cluster_offset + s->cluster_size - 1) &
 | 
					            cluster_offset = (cluster_offset + s->cluster_size - 1) &
 | 
				
			||||||
                ~(s->cluster_size - 1);
 | 
					                ~(s->cluster_size - 1);
 | 
				
			||||||
            /* write the cluster content */
 | 
					            /* 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)
 | 
					                s->cluster_size)
 | 
				
			||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            cluster_offset = bdrv_getlength(bs->file);
 | 
					            cluster_offset = bdrv_getlength(s->hd);
 | 
				
			||||||
            if (allocate == 1) {
 | 
					            if (allocate == 1) {
 | 
				
			||||||
                /* round to cluster size */
 | 
					                /* round to cluster size */
 | 
				
			||||||
                cluster_offset = (cluster_offset + s->cluster_size - 1) &
 | 
					                cluster_offset = (cluster_offset + s->cluster_size - 1) &
 | 
				
			||||||
                    ~(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
 | 
					                /* if encrypted, we must initialize the cluster
 | 
				
			||||||
                   content which won't be written */
 | 
					                   content which won't be written */
 | 
				
			||||||
                if (s->crypt_method &&
 | 
					                if (s->crypt_method &&
 | 
				
			||||||
@@ -365,7 +359,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
				
			|||||||
                                            s->cluster_data,
 | 
					                                            s->cluster_data,
 | 
				
			||||||
                                            s->cluster_data + 512, 1, 1,
 | 
					                                            s->cluster_data + 512, 1, 1,
 | 
				
			||||||
                                            &s->aes_encrypt_key);
 | 
					                                            &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)
 | 
					                                            s->cluster_data, 512) != 512)
 | 
				
			||||||
                                return -1;
 | 
					                                return -1;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@@ -379,23 +373,21 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
 | 
				
			|||||||
        /* update L2 table */
 | 
					        /* update L2 table */
 | 
				
			||||||
        tmp = cpu_to_be64(cluster_offset);
 | 
					        tmp = cpu_to_be64(cluster_offset);
 | 
				
			||||||
        l2_table[l2_index] = tmp;
 | 
					        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)
 | 
					                &tmp, sizeof(tmp)) < 0)
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return cluster_offset;
 | 
					    return cluster_offset;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn qcow_co_is_allocated(BlockDriverState *bs,
 | 
					static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
        int64_t sector_num, int nb_sectors, int *pnum)
 | 
					                             int nb_sectors, int *pnum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcowState *s = bs->opaque;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    int index_in_cluster, n;
 | 
					    int index_in_cluster, n;
 | 
				
			||||||
    uint64_t cluster_offset;
 | 
					    uint64_t cluster_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_co_mutex_lock(&s->lock);
 | 
					 | 
				
			||||||
    cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
 | 
					    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);
 | 
					    index_in_cluster = sector_num & (s->cluster_sectors - 1);
 | 
				
			||||||
    n = s->cluster_sectors - index_in_cluster;
 | 
					    n = s->cluster_sectors - index_in_cluster;
 | 
				
			||||||
    if (n > nb_sectors)
 | 
					    if (n > nb_sectors)
 | 
				
			||||||
@@ -431,9 +423,8 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
 | 
				
			|||||||
    return 0;
 | 
					    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;
 | 
					    int ret, csize;
 | 
				
			||||||
    uint64_t coffset;
 | 
					    uint64_t coffset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -441,7 +432,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
 | 
				
			|||||||
    if (s->cluster_cache_offset != coffset) {
 | 
					    if (s->cluster_cache_offset != coffset) {
 | 
				
			||||||
        csize = cluster_offset >> (63 - s->cluster_bits);
 | 
					        csize = cluster_offset >> (63 - s->cluster_bits);
 | 
				
			||||||
        csize &= (s->cluster_size - 1);
 | 
					        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)
 | 
					        if (ret != csize)
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
        if (decompress_buffer(s->cluster_cache, s->cluster_size,
 | 
					        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;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
 | 
					#if 0
 | 
				
			||||||
                         int nb_sectors, QEMUIOVector *qiov)
 | 
					
 | 
				
			||||||
 | 
					static int qcow_read(BlockDriverState *bs, int64_t sector_num,
 | 
				
			||||||
 | 
					                     uint8_t *buf, int nb_sectors)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcowState *s = bs->opaque;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    int index_in_cluster;
 | 
					    int ret, index_in_cluster, n;
 | 
				
			||||||
    int ret = 0, n;
 | 
					 | 
				
			||||||
    uint64_t cluster_offset;
 | 
					    uint64_t cluster_offset;
 | 
				
			||||||
    struct iovec hd_iov;
 | 
					 | 
				
			||||||
    QEMUIOVector hd_qiov;
 | 
					 | 
				
			||||||
    uint8_t *buf;
 | 
					 | 
				
			||||||
    void *orig_buf;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (qiov->niov > 1) {
 | 
					    while (nb_sectors > 0) {
 | 
				
			||||||
        buf = orig_buf = qemu_blockalign(bs, qiov->size);
 | 
					        cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
 | 
				
			||||||
    } 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);
 | 
					 | 
				
			||||||
        index_in_cluster = sector_num & (s->cluster_sectors - 1);
 | 
					        index_in_cluster = sector_num & (s->cluster_sectors - 1);
 | 
				
			||||||
        n = s->cluster_sectors - index_in_cluster;
 | 
					        n = s->cluster_sectors - index_in_cluster;
 | 
				
			||||||
        if (n > nb_sectors) {
 | 
					        if (n > nb_sectors)
 | 
				
			||||||
            n = nb_sectors;
 | 
					            n = nb_sectors;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!cluster_offset) {
 | 
					        if (!cluster_offset) {
 | 
				
			||||||
            if (bs->backing_hd) {
 | 
					            if (bs->backing_hd) {
 | 
				
			||||||
                /* read from the base image */
 | 
					                /* read from the base image */
 | 
				
			||||||
                hd_iov.iov_base = (void *)buf;
 | 
					                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
 | 
				
			||||||
                hd_iov.iov_len = n * 512;
 | 
					                if (ret < 0)
 | 
				
			||||||
                qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
 | 
					                    return -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;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                /* Note: in this case, no need to wait */
 | 
					 | 
				
			||||||
                memset(buf, 0, 512 * n);
 | 
					                memset(buf, 0, 512 * n);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
 | 
					        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
 | 
				
			||||||
            /* add AIO support for compressed blocks ? */
 | 
					            if (decompress_cluster(s, cluster_offset) < 0)
 | 
				
			||||||
            if (decompress_cluster(bs, cluster_offset) < 0) {
 | 
					                return -1;
 | 
				
			||||||
                goto fail;
 | 
					            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            memcpy(buf,
 | 
					 | 
				
			||||||
                   s->cluster_cache + index_in_cluster * 512, 512 * n);
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if ((cluster_offset & 511) != 0) {
 | 
					            ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
 | 
				
			||||||
                goto fail;
 | 
					            if (ret != n * 512)
 | 
				
			||||||
            }
 | 
					                return -1;
 | 
				
			||||||
            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;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (s->crypt_method) {
 | 
					            if (s->crypt_method) {
 | 
				
			||||||
                encrypt_sectors(s, sector_num, buf, buf,
 | 
					                encrypt_sectors(s, sector_num, buf, buf, n, 0,
 | 
				
			||||||
                                n, 0,
 | 
					 | 
				
			||||||
                                &s->aes_decrypt_key);
 | 
					                                &s->aes_decrypt_key);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ret = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        nb_sectors -= n;
 | 
					        nb_sectors -= n;
 | 
				
			||||||
        sector_num += n;
 | 
					        sector_num += n;
 | 
				
			||||||
        buf += n * 512;
 | 
					        buf += n * 512;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
done:
 | 
					typedef struct QCowAIOCB {
 | 
				
			||||||
    qemu_co_mutex_unlock(&s->lock);
 | 
					    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) {
 | 
					static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
 | 
				
			||||||
        qemu_iovec_from_buf(qiov, 0, orig_buf, qiov->size);
 | 
					{
 | 
				
			||||||
        qemu_vfree(orig_buf);
 | 
					    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
 | 
				
			||||||
    }
 | 
					    if (acb->hd_aiocb)
 | 
				
			||||||
 | 
					        bdrv_aio_cancel(acb->hd_aiocb);
 | 
				
			||||||
    return ret;
 | 
					    qemu_aio_release(acb);
 | 
				
			||||||
 | 
					 | 
				
			||||||
fail:
 | 
					 | 
				
			||||||
    ret = -EIO;
 | 
					 | 
				
			||||||
    goto done;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
 | 
					static AIOPool qcow_aio_pool = {
 | 
				
			||||||
                          int nb_sectors, QEMUIOVector *qiov)
 | 
					    .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;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    int index_in_cluster;
 | 
					    int index_in_cluster;
 | 
				
			||||||
    uint64_t cluster_offset;
 | 
					    uint64_t cluster_offset;
 | 
				
			||||||
    const uint8_t *src_buf;
 | 
					    const uint8_t *src_buf;
 | 
				
			||||||
    int ret = 0, n;
 | 
					
 | 
				
			||||||
    uint8_t *cluster_data = NULL;
 | 
					    acb->hd_aiocb = NULL;
 | 
				
			||||||
    struct iovec hd_iov;
 | 
					
 | 
				
			||||||
    QEMUIOVector hd_qiov;
 | 
					    if (ret < 0)
 | 
				
			||||||
    uint8_t *buf;
 | 
					        goto done;
 | 
				
			||||||
    void *orig_buf;
 | 
					
 | 
				
			||||||
 | 
					    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 */
 | 
					    s->cluster_cache_offset = -1; /* disable compressed cache */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (qiov->niov > 1) {
 | 
					    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 | 
				
			||||||
        buf = orig_buf = qemu_blockalign(bs, qiov->size);
 | 
					    if (!acb)
 | 
				
			||||||
        qemu_iovec_to_buf(qiov, 0, buf, qiov->size);
 | 
					        return NULL;
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        orig_buf = NULL;
 | 
					 | 
				
			||||||
        buf = (uint8_t *)qiov->iov->iov_base;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_co_mutex_lock(&s->lock);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (nb_sectors != 0) {
 | 
					    qcow_aio_write_cb(acb, 0);
 | 
				
			||||||
 | 
					    return &acb->common;
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void qcow_close(BlockDriverState *bs)
 | 
					static void qcow_close(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcowState *s = bs->opaque;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
 | 
					    qemu_free(s->l1_table);
 | 
				
			||||||
    g_free(s->l1_table);
 | 
					    qemu_free(s->l2_cache);
 | 
				
			||||||
    g_free(s->l2_cache);
 | 
					    qemu_free(s->cluster_cache);
 | 
				
			||||||
    g_free(s->cluster_cache);
 | 
					    qemu_free(s->cluster_data);
 | 
				
			||||||
    g_free(s->cluster_data);
 | 
					    bdrv_delete(s->hd);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    migrate_del_blocker(s->migration_blocker);
 | 
					 | 
				
			||||||
    error_free(s->migration_blocker);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qcow_create(const char *filename, QEMUOptionParameter *options)
 | 
					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;
 | 
					    QCowHeader header;
 | 
				
			||||||
    uint8_t *tmp;
 | 
					    uint64_t tmp;
 | 
				
			||||||
    int64_t total_size = 0;
 | 
					    int64_t total_size = 0;
 | 
				
			||||||
    const char *backing_file = NULL;
 | 
					    const char *backing_file = NULL;
 | 
				
			||||||
    int flags = 0;
 | 
					    int flags = 0;
 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
    BlockDriverState *qcow_bs;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Read out options */
 | 
					    /* Read out options */
 | 
				
			||||||
    while (options && options->name) {
 | 
					    while (options && options->name) {
 | 
				
			||||||
@@ -665,21 +764,9 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
 | 
				
			|||||||
        options++;
 | 
					        options++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = bdrv_create_file(filename, options);
 | 
					    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (fd < 0)
 | 
				
			||||||
        return ret;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memset(&header, 0, sizeof(header));
 | 
					    memset(&header, 0, sizeof(header));
 | 
				
			||||||
    header.magic = cpu_to_be32(QCOW_MAGIC);
 | 
					    header.magic = cpu_to_be32(QCOW_MAGIC);
 | 
				
			||||||
    header.version = cpu_to_be32(QCOW_VERSION);
 | 
					    header.version = cpu_to_be32(QCOW_VERSION);
 | 
				
			||||||
@@ -715,35 +802,17 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* write all the data */
 | 
					    /* write all the data */
 | 
				
			||||||
    ret = bdrv_pwrite(qcow_bs, 0, &header, sizeof(header));
 | 
					    write(fd, &header, sizeof(header));
 | 
				
			||||||
    if (ret != sizeof(header)) {
 | 
					 | 
				
			||||||
        goto exit;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (backing_file) {
 | 
					    if (backing_file) {
 | 
				
			||||||
        ret = bdrv_pwrite(qcow_bs, sizeof(header),
 | 
					        write(fd, backing_file, backing_filename_len);
 | 
				
			||||||
            backing_file, backing_filename_len);
 | 
					 | 
				
			||||||
        if (ret != backing_filename_len) {
 | 
					 | 
				
			||||||
            goto exit;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    lseek(fd, header_size, SEEK_SET);
 | 
				
			||||||
    tmp = g_malloc0(BDRV_SECTOR_SIZE);
 | 
					    tmp = 0;
 | 
				
			||||||
    for (i = 0; i < ((sizeof(uint64_t)*l1_size + BDRV_SECTOR_SIZE - 1)/
 | 
					    for(i = 0;i < l1_size; i++) {
 | 
				
			||||||
        BDRV_SECTOR_SIZE); i++) {
 | 
					        write(fd, &tmp, sizeof(tmp));
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
    g_free(tmp);
 | 
					    return 0;
 | 
				
			||||||
    ret = 0;
 | 
					 | 
				
			||||||
exit:
 | 
					 | 
				
			||||||
    bdrv_delete(qcow_bs);
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qcow_make_empty(BlockDriverState *bs)
 | 
					static int qcow_make_empty(BlockDriverState *bs)
 | 
				
			||||||
@@ -753,10 +822,10 @@ static int qcow_make_empty(BlockDriverState *bs)
 | 
				
			|||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memset(s->l1_table, 0, l1_length);
 | 
					    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)
 | 
					            l1_length) < 0)
 | 
				
			||||||
        return -1;
 | 
					        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)
 | 
					    if (ret < 0)
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -781,7 +850,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
    if (nb_sectors != s->cluster_sectors)
 | 
					    if (nb_sectors != s->cluster_sectors)
 | 
				
			||||||
        return -EINVAL;
 | 
					        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 */
 | 
					    /* best compression, small window, no zlib header */
 | 
				
			||||||
    memset(&strm, 0, sizeof(strm));
 | 
					    memset(&strm, 0, sizeof(strm));
 | 
				
			||||||
@@ -789,8 +860,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
                       Z_DEFLATED, -12,
 | 
					                       Z_DEFLATED, -12,
 | 
				
			||||||
                       9, Z_DEFAULT_STRATEGY);
 | 
					                       9, Z_DEFAULT_STRATEGY);
 | 
				
			||||||
    if (ret != 0) {
 | 
					    if (ret != 0) {
 | 
				
			||||||
        ret = -EINVAL;
 | 
					        qemu_free(out_buf);
 | 
				
			||||||
        goto fail;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strm.avail_in = s->cluster_size;
 | 
					    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);
 | 
					    ret = deflate(&strm, Z_FINISH);
 | 
				
			||||||
    if (ret != Z_STREAM_END && ret != Z_OK) {
 | 
					    if (ret != Z_STREAM_END && ret != Z_OK) {
 | 
				
			||||||
 | 
					        qemu_free(out_buf);
 | 
				
			||||||
        deflateEnd(&strm);
 | 
					        deflateEnd(&strm);
 | 
				
			||||||
        ret = -EINVAL;
 | 
					        return -1;
 | 
				
			||||||
        goto fail;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    out_len = strm.next_out - out_buf;
 | 
					    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) {
 | 
					    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
 | 
				
			||||||
        /* could not compress: write normal cluster */
 | 
					        /* could not compress: write normal cluster */
 | 
				
			||||||
        ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
 | 
					        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
 | 
				
			||||||
        if (ret < 0) {
 | 
					 | 
				
			||||||
            goto fail;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
 | 
					        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
 | 
				
			||||||
                                            out_len, 0, 0);
 | 
					                                            out_len, 0, 0);
 | 
				
			||||||
        if (cluster_offset == 0) {
 | 
					 | 
				
			||||||
            ret = -EIO;
 | 
					 | 
				
			||||||
            goto fail;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cluster_offset &= s->cluster_offset_mask;
 | 
					        cluster_offset &= s->cluster_offset_mask;
 | 
				
			||||||
        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
 | 
					        if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
 | 
				
			||||||
        if (ret < 0) {
 | 
					            qemu_free(out_buf);
 | 
				
			||||||
            goto fail;
 | 
					            return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = 0;
 | 
					    qemu_free(out_buf);
 | 
				
			||||||
fail:
 | 
					    return 0;
 | 
				
			||||||
    g_free(out_buf);
 | 
					}
 | 
				
			||||||
    return ret;
 | 
					
 | 
				
			||||||
 | 
					static void qcow_flush(BlockDriverState *bs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
 | 
					    bdrv_flush(s->hd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | 
					static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | 
				
			||||||
@@ -869,15 +936,14 @@ static BlockDriver bdrv_qcow = {
 | 
				
			|||||||
    .bdrv_open		= qcow_open,
 | 
					    .bdrv_open		= qcow_open,
 | 
				
			||||||
    .bdrv_close		= qcow_close,
 | 
					    .bdrv_close		= qcow_close,
 | 
				
			||||||
    .bdrv_create	= qcow_create,
 | 
					    .bdrv_create	= qcow_create,
 | 
				
			||||||
 | 
					    .bdrv_flush		= qcow_flush,
 | 
				
			||||||
    .bdrv_co_readv          = qcow_co_readv,
 | 
					    .bdrv_is_allocated	= qcow_is_allocated,
 | 
				
			||||||
    .bdrv_co_writev         = qcow_co_writev,
 | 
					    .bdrv_set_key	= qcow_set_key,
 | 
				
			||||||
    .bdrv_co_is_allocated   = qcow_co_is_allocated,
 | 
					    .bdrv_make_empty	= qcow_make_empty,
 | 
				
			||||||
 | 
					    .bdrv_aio_readv	= qcow_aio_readv,
 | 
				
			||||||
    .bdrv_set_key           = qcow_set_key,
 | 
					    .bdrv_aio_writev	= qcow_aio_writev,
 | 
				
			||||||
    .bdrv_make_empty        = qcow_make_empty,
 | 
					    .bdrv_write_compressed = qcow_write_compressed,
 | 
				
			||||||
    .bdrv_write_compressed  = qcow_write_compressed,
 | 
					    .bdrv_get_info	= qcow_get_info,
 | 
				
			||||||
    .bdrv_get_info          = qcow_get_info,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .create_options = qcow_create_options,
 | 
					    .create_options = qcow_create_options,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,323 +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;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												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_int.h"
 | 
				
			||||||
#include "block/qcow2.h"
 | 
					#include "block/qcow2.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct QEMU_PACKED QCowSnapshotHeader {
 | 
					typedef struct __attribute__((packed)) QCowSnapshotHeader {
 | 
				
			||||||
    /* header is 8 byte aligned */
 | 
					    /* header is 8 byte aligned */
 | 
				
			||||||
    uint64_t l1_table_offset;
 | 
					    uint64_t l1_table_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,21 +46,16 @@ typedef struct QEMU_PACKED QCowSnapshotHeader {
 | 
				
			|||||||
    /* name follows  */
 | 
					    /* name follows  */
 | 
				
			||||||
} QCowSnapshotHeader;
 | 
					} QCowSnapshotHeader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct QEMU_PACKED QCowSnapshotExtraData {
 | 
					 | 
				
			||||||
    uint64_t vm_state_size_large;
 | 
					 | 
				
			||||||
    uint64_t disk_size;
 | 
					 | 
				
			||||||
} QCowSnapshotExtraData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void qcow2_free_snapshots(BlockDriverState *bs)
 | 
					void qcow2_free_snapshots(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcowState *s = bs->opaque;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for(i = 0; i < s->nb_snapshots; i++) {
 | 
					    for(i = 0; i < s->nb_snapshots; i++) {
 | 
				
			||||||
        g_free(s->snapshots[i].name);
 | 
					        qemu_free(s->snapshots[i].name);
 | 
				
			||||||
        g_free(s->snapshots[i].id_str);
 | 
					        qemu_free(s->snapshots[i].id_str);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    g_free(s->snapshots);
 | 
					    qemu_free(s->snapshots);
 | 
				
			||||||
    s->snapshots = NULL;
 | 
					    s->snapshots = NULL;
 | 
				
			||||||
    s->nb_snapshots = 0;
 | 
					    s->nb_snapshots = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -69,12 +64,10 @@ int qcow2_read_snapshots(BlockDriverState *bs)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcowState *s = bs->opaque;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    QCowSnapshotHeader h;
 | 
					    QCowSnapshotHeader h;
 | 
				
			||||||
    QCowSnapshotExtraData extra;
 | 
					 | 
				
			||||||
    QCowSnapshot *sn;
 | 
					    QCowSnapshot *sn;
 | 
				
			||||||
    int i, id_str_size, name_size;
 | 
					    int i, id_str_size, name_size;
 | 
				
			||||||
    int64_t offset;
 | 
					    int64_t offset;
 | 
				
			||||||
    uint32_t extra_data_size;
 | 
					    uint32_t extra_data_size;
 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!s->nb_snapshots) {
 | 
					    if (!s->nb_snapshots) {
 | 
				
			||||||
        s->snapshots = NULL;
 | 
					        s->snapshots = NULL;
 | 
				
			||||||
@@ -83,16 +76,11 @@ int qcow2_read_snapshots(BlockDriverState *bs)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    offset = s->snapshots_offset;
 | 
					    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++) {
 | 
					    for(i = 0; i < s->nb_snapshots; i++) {
 | 
				
			||||||
        /* Read statically sized part of the snapshot header */
 | 
					 | 
				
			||||||
        offset = align_offset(offset, 8);
 | 
					        offset = align_offset(offset, 8);
 | 
				
			||||||
        ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
 | 
					        if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
 | 
				
			||||||
        if (ret < 0) {
 | 
					 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        offset += sizeof(h);
 | 
					        offset += sizeof(h);
 | 
				
			||||||
        sn = s->snapshots + i;
 | 
					        sn = s->snapshots + i;
 | 
				
			||||||
        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
 | 
					        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);
 | 
					        id_str_size = be16_to_cpu(h.id_str_size);
 | 
				
			||||||
        name_size = be16_to_cpu(h.name_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;
 | 
					        offset += extra_data_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (extra_data_size >= 8) {
 | 
					        sn->id_str = qemu_malloc(id_str_size + 1);
 | 
				
			||||||
            sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
 | 
					        if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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) {
 | 
					 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        offset += id_str_size;
 | 
					        offset += id_str_size;
 | 
				
			||||||
        sn->id_str[id_str_size] = '\0';
 | 
					        sn->id_str[id_str_size] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Read snapshot name */
 | 
					        sn->name = qemu_malloc(name_size + 1);
 | 
				
			||||||
        sn->name = g_malloc(name_size + 1);
 | 
					        if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
 | 
				
			||||||
        ret = bdrv_pread(bs->file, offset, sn->name, name_size);
 | 
					 | 
				
			||||||
        if (ret < 0) {
 | 
					 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        offset += name_size;
 | 
					        offset += name_size;
 | 
				
			||||||
        sn->name[name_size] = '\0';
 | 
					        sn->name[name_size] = '\0';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    s->snapshots_size = offset - s->snapshots_offset;
 | 
					    s->snapshots_size = offset - s->snapshots_offset;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					 fail:
 | 
				
			||||||
fail:
 | 
					 | 
				
			||||||
    qcow2_free_snapshots(bs);
 | 
					    qcow2_free_snapshots(bs);
 | 
				
			||||||
    return ret;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* add at the end of the file a new list of snapshots */
 | 
					/* 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;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    QCowSnapshot *sn;
 | 
					    QCowSnapshot *sn;
 | 
				
			||||||
    QCowSnapshotHeader h;
 | 
					    QCowSnapshotHeader h;
 | 
				
			||||||
    QCowSnapshotExtraData extra;
 | 
					 | 
				
			||||||
    int i, name_size, id_str_size, snapshots_size;
 | 
					    int i, name_size, id_str_size, snapshots_size;
 | 
				
			||||||
    struct {
 | 
					    uint64_t data64;
 | 
				
			||||||
        uint32_t nb_snapshots;
 | 
					    uint32_t data32;
 | 
				
			||||||
        uint64_t snapshots_offset;
 | 
					 | 
				
			||||||
    } QEMU_PACKED header_data;
 | 
					 | 
				
			||||||
    int64_t offset, snapshots_offset;
 | 
					    int64_t offset, snapshots_offset;
 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* compute the size of the snapshots */
 | 
					    /* compute the size of the snapshots */
 | 
				
			||||||
    offset = 0;
 | 
					    offset = 0;
 | 
				
			||||||
@@ -172,100 +132,60 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
 | 
				
			|||||||
        sn = s->snapshots + i;
 | 
					        sn = s->snapshots + i;
 | 
				
			||||||
        offset = align_offset(offset, 8);
 | 
					        offset = align_offset(offset, 8);
 | 
				
			||||||
        offset += sizeof(h);
 | 
					        offset += sizeof(h);
 | 
				
			||||||
        offset += sizeof(extra);
 | 
					 | 
				
			||||||
        offset += strlen(sn->id_str);
 | 
					        offset += strlen(sn->id_str);
 | 
				
			||||||
        offset += strlen(sn->name);
 | 
					        offset += strlen(sn->name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    snapshots_size = offset;
 | 
					    snapshots_size = offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Allocate space for the new snapshot list */
 | 
					 | 
				
			||||||
    snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
 | 
					    snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
 | 
				
			||||||
    bdrv_flush(bs->file);
 | 
					 | 
				
			||||||
    offset = snapshots_offset;
 | 
					    offset = snapshots_offset;
 | 
				
			||||||
    if (offset < 0) {
 | 
					    if (offset < 0) {
 | 
				
			||||||
        return offset;
 | 
					        return offset;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Write all snapshots to the new list */
 | 
					 | 
				
			||||||
    for(i = 0; i < s->nb_snapshots; i++) {
 | 
					    for(i = 0; i < s->nb_snapshots; i++) {
 | 
				
			||||||
        sn = s->snapshots + i;
 | 
					        sn = s->snapshots + i;
 | 
				
			||||||
        memset(&h, 0, sizeof(h));
 | 
					        memset(&h, 0, sizeof(h));
 | 
				
			||||||
        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
 | 
					        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
 | 
				
			||||||
        h.l1_size = cpu_to_be32(sn->l1_size);
 | 
					        h.l1_size = cpu_to_be32(sn->l1_size);
 | 
				
			||||||
        /* If it doesn't fit in 32 bit, older implementations should treat it
 | 
					        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
 | 
				
			||||||
         * 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_sec = cpu_to_be32(sn->date_sec);
 | 
				
			||||||
        h.date_nsec = cpu_to_be32(sn->date_nsec);
 | 
					        h.date_nsec = cpu_to_be32(sn->date_nsec);
 | 
				
			||||||
        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_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);
 | 
					        id_str_size = strlen(sn->id_str);
 | 
				
			||||||
        name_size = strlen(sn->name);
 | 
					        name_size = strlen(sn->name);
 | 
				
			||||||
        h.id_str_size = cpu_to_be16(id_str_size);
 | 
					        h.id_str_size = cpu_to_be16(id_str_size);
 | 
				
			||||||
        h.name_size = cpu_to_be16(name_size);
 | 
					        h.name_size = cpu_to_be16(name_size);
 | 
				
			||||||
        offset = align_offset(offset, 8);
 | 
					        offset = align_offset(offset, 8);
 | 
				
			||||||
 | 
					        if (bdrv_pwrite_sync(s->hd, offset, &h, sizeof(h)) < 0)
 | 
				
			||||||
        ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
 | 
					 | 
				
			||||||
        if (ret < 0) {
 | 
					 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        offset += sizeof(h);
 | 
					        offset += sizeof(h);
 | 
				
			||||||
 | 
					        if (bdrv_pwrite_sync(s->hd, offset, sn->id_str, id_str_size) < 0)
 | 
				
			||||||
        ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra));
 | 
					 | 
				
			||||||
        if (ret < 0) {
 | 
					 | 
				
			||||||
            goto fail;
 | 
					            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;
 | 
					        offset += id_str_size;
 | 
				
			||||||
 | 
					        if (bdrv_pwrite_sync(s->hd, offset, sn->name, name_size) < 0)
 | 
				
			||||||
        ret = bdrv_pwrite(bs->file, offset, sn->name, name_size);
 | 
					 | 
				
			||||||
        if (ret < 0) {
 | 
					 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        offset += name_size;
 | 
					        offset += name_size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /* update the various header fields */
 | 
				
			||||||
     * Update the header to point to the new snapshot table. This requires the
 | 
					    data64 = cpu_to_be64(snapshots_offset);
 | 
				
			||||||
     * new table and its refcounts to be stable on disk.
 | 
					    if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, snapshots_offset),
 | 
				
			||||||
     */
 | 
					                    &data64, sizeof(data64)) < 0)
 | 
				
			||||||
    ret = bdrv_flush(bs);
 | 
					 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    data32 = cpu_to_be32(s->nb_snapshots);
 | 
				
			||||||
 | 
					    if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, nb_snapshots),
 | 
				
			||||||
    QEMU_BUILD_BUG_ON(offsetof(QCowHeader, snapshots_offset) !=
 | 
					                    &data32, sizeof(data32)) < 0)
 | 
				
			||||||
        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) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* free the old snapshot table */
 | 
					    /* free the old snapshot table */
 | 
				
			||||||
    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
 | 
					    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
 | 
				
			||||||
    s->snapshots_offset = snapshots_offset;
 | 
					    s->snapshots_offset = snapshots_offset;
 | 
				
			||||||
    s->snapshots_size = snapshots_size;
 | 
					    s->snapshots_size = snapshots_size;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					 fail:
 | 
				
			||||||
fail:
 | 
					    return -1;
 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void find_new_snapshot_id(BlockDriverState *bs,
 | 
					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)
 | 
					int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcowState *s = bs->opaque;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    QCowSnapshot *new_snapshot_list = NULL;
 | 
					    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
 | 
				
			||||||
    QCowSnapshot *old_snapshot_list = NULL;
 | 
					 | 
				
			||||||
    QCowSnapshot sn1, *sn = &sn1;
 | 
					 | 
				
			||||||
    int i, ret;
 | 
					    int i, ret;
 | 
				
			||||||
    uint64_t *l1_table = NULL;
 | 
					    uint64_t *l1_table = NULL;
 | 
				
			||||||
    int64_t l1_table_offset;
 | 
					    int64_t l1_table_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memset(sn, 0, sizeof(*sn));
 | 
					    memset(sn, 0, sizeof(*sn));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Generate an ID if it wasn't passed */
 | 
					 | 
				
			||||||
    if (sn_info->id_str[0] == '\0') {
 | 
					    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));
 | 
					        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Check that the ID is unique */
 | 
					    /* check that the ID is unique */
 | 
				
			||||||
    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) {
 | 
					    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
 | 
				
			||||||
        return -EEXIST;
 | 
					        return -ENOENT;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Populate sn with passed data */
 | 
					    sn->id_str = qemu_strdup(sn_info->id_str);
 | 
				
			||||||
    sn->id_str = g_strdup(sn_info->id_str);
 | 
					    if (!sn->id_str)
 | 
				
			||||||
    sn->name = g_strdup(sn_info->name);
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    sn->name = qemu_strdup(sn_info->name);
 | 
				
			||||||
    sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
 | 
					    if (!sn->name)
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
    sn->vm_state_size = sn_info->vm_state_size;
 | 
					    sn->vm_state_size = sn_info->vm_state_size;
 | 
				
			||||||
    sn->date_sec = sn_info->date_sec;
 | 
					    sn->date_sec = sn_info->date_sec;
 | 
				
			||||||
    sn->date_nsec = sn_info->date_nsec;
 | 
					    sn->date_nsec = sn_info->date_nsec;
 | 
				
			||||||
    sn->vm_clock_nsec = sn_info->vm_clock_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));
 | 
					    l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
 | 
				
			||||||
    if (l1_table_offset < 0) {
 | 
					    if (l1_table_offset < 0) {
 | 
				
			||||||
        ret = l1_table_offset;
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sn->l1_table_offset = l1_table_offset;
 | 
					    sn->l1_table_offset = l1_table_offset;
 | 
				
			||||||
    sn->l1_size = s->l1_size;
 | 
					    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++) {
 | 
					    for(i = 0; i < s->l1_size; i++) {
 | 
				
			||||||
        l1_table[i] = cpu_to_be64(s->l1_table[i]);
 | 
					        l1_table[i] = cpu_to_be64(s->l1_table[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (bdrv_pwrite_sync(s->hd, sn->l1_table_offset,
 | 
				
			||||||
    ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
 | 
					                    l1_table, s->l1_size * sizeof(uint64_t)) < 0)
 | 
				
			||||||
                      s->l1_size * sizeof(uint64_t));
 | 
					 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    qemu_free(l1_table);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_free(l1_table);
 | 
					 | 
				
			||||||
    l1_table = NULL;
 | 
					    l1_table = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
 | 
				
			||||||
     * 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));
 | 
					 | 
				
			||||||
    if (s->snapshots) {
 | 
					    if (s->snapshots) {
 | 
				
			||||||
        memcpy(new_snapshot_list, s->snapshots,
 | 
					        memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
 | 
				
			||||||
               s->nb_snapshots * sizeof(QCowSnapshot));
 | 
					        qemu_free(s->snapshots);
 | 
				
			||||||
        old_snapshot_list = s->snapshots;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    s->snapshots = new_snapshot_list;
 | 
					    s->snapshots = snapshots1;
 | 
				
			||||||
    s->snapshots[s->nb_snapshots++] = *sn;
 | 
					    s->snapshots[s->nb_snapshots++] = *sn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = qcow2_write_snapshots(bs);
 | 
					    if (qcow_write_snapshots(bs) < 0)
 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        g_free(s->snapshots);
 | 
					 | 
				
			||||||
        s->snapshots = old_snapshot_list;
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_free(old_snapshot_list);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef DEBUG_ALLOC
 | 
					#ifdef DEBUG_ALLOC
 | 
				
			||||||
    {
 | 
					    qcow2_check_refcounts(bs);
 | 
				
			||||||
      BdrvCheckResult result = {0};
 | 
					 | 
				
			||||||
      qcow2_check_refcounts(bs, &result, 0);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					 fail:
 | 
				
			||||||
fail:
 | 
					    qemu_free(sn->name);
 | 
				
			||||||
    g_free(sn->id_str);
 | 
					    qemu_free(l1_table);
 | 
				
			||||||
    g_free(sn->name);
 | 
					    return -1;
 | 
				
			||||||
    g_free(l1_table);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* copy the snapshot 'snapshot_name' into the current disk image */
 | 
					/* 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;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    QCowSnapshot *sn;
 | 
					    QCowSnapshot *sn;
 | 
				
			||||||
    int i, snapshot_index;
 | 
					    int i, snapshot_index, l1_size2;
 | 
				
			||||||
    int cur_l1_bytes, sn_l1_bytes;
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
    uint64_t *sn_l1_table = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Search the snapshot */
 | 
					 | 
				
			||||||
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
 | 
					    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
 | 
				
			||||||
    if (snapshot_index < 0) {
 | 
					    if (snapshot_index < 0)
 | 
				
			||||||
        return -ENOENT;
 | 
					        return -ENOENT;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    sn = &s->snapshots[snapshot_index];
 | 
					    sn = &s->snapshots[snapshot_index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
 | 
					    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
 | 
				
			||||||
        error_report("qcow2: Loading snapshots with different disk "
 | 
					 | 
				
			||||||
            "size is not implemented");
 | 
					 | 
				
			||||||
        ret = -ENOTSUP;
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    if (qcow2_grow_l1_table(bs, sn->l1_size) < 0)
 | 
				
			||||||
     * 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) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cur_l1_bytes = s->l1_size * sizeof(uint64_t);
 | 
					    s->l1_size = sn->l1_size;
 | 
				
			||||||
    sn_l1_bytes = sn->l1_size * sizeof(uint64_t);
 | 
					    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,
 | 
				
			||||||
     * Copy the snapshot L1 table to the current L1 table.
 | 
					                   s->l1_table, l1_size2) != l1_size2)
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * 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) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    if (bdrv_pwrite_sync(s->hd, s->l1_table_offset,
 | 
				
			||||||
 | 
					                    s->l1_table, l1_size2) < 0)
 | 
				
			||||||
    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset,
 | 
					 | 
				
			||||||
                                         sn->l1_size, 1);
 | 
					 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        goto fail;
 | 
					        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++) {
 | 
					    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;
 | 
					        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
 | 
					#ifdef DEBUG_ALLOC
 | 
				
			||||||
    {
 | 
					    qcow2_check_refcounts(bs);
 | 
				
			||||||
        BdrvCheckResult result = {0};
 | 
					 | 
				
			||||||
        qcow2_check_refcounts(bs, &result, 0);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					 fail:
 | 
				
			||||||
fail:
 | 
					    return -EIO;
 | 
				
			||||||
    g_free(sn_l1_table);
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
 | 
					int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVQcowState *s = bs->opaque;
 | 
					    BDRVQcowState *s = bs->opaque;
 | 
				
			||||||
    QCowSnapshot sn;
 | 
					    QCowSnapshot *sn;
 | 
				
			||||||
    int snapshot_index, ret;
 | 
					    int snapshot_index, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Search the snapshot */
 | 
					 | 
				
			||||||
    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
 | 
					    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
 | 
				
			||||||
    if (snapshot_index < 0) {
 | 
					    if (snapshot_index < 0)
 | 
				
			||||||
        return -ENOENT;
 | 
					        return -ENOENT;
 | 
				
			||||||
    }
 | 
					    sn = &s->snapshots[snapshot_index];
 | 
				
			||||||
    sn = s->snapshots[snapshot_index];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Remove it from the snapshot list */
 | 
					    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
 | 
				
			||||||
    memmove(s->snapshots + snapshot_index,
 | 
					    if (ret < 0)
 | 
				
			||||||
            s->snapshots + snapshot_index + 1,
 | 
					 | 
				
			||||||
            (s->nb_snapshots - snapshot_index - 1) * sizeof(sn));
 | 
					 | 
				
			||||||
    s->nb_snapshots--;
 | 
					 | 
				
			||||||
    ret = qcow2_write_snapshots(bs);
 | 
					 | 
				
			||||||
    if (ret < 0) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					        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 */
 | 
					    /* must update the copied flag on the current cluster offsets */
 | 
				
			||||||
    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
 | 
					    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) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        /* XXX: restore snapshot if error ? */
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef DEBUG_ALLOC
 | 
					#ifdef DEBUG_ALLOC
 | 
				
			||||||
    {
 | 
					    qcow2_check_refcounts(bs);
 | 
				
			||||||
        BdrvCheckResult result = {0};
 | 
					 | 
				
			||||||
        qcow2_check_refcounts(bs, &result, 0);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -600,7 +399,7 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 | 
				
			|||||||
        return s->nb_snapshots;
 | 
					        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++) {
 | 
					    for(i = 0; i < s->nb_snapshots; i++) {
 | 
				
			||||||
        sn_info = sn_tab + i;
 | 
					        sn_info = sn_tab + i;
 | 
				
			||||||
        sn = s->snapshots + i;
 | 
					        sn = s->snapshots + i;
 | 
				
			||||||
@@ -617,44 +416,3 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 | 
				
			|||||||
    return s->nb_snapshots;
 | 
					    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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1730
									
								
								block/qcow2.c
									
									
									
									
									
								
							
							
						
						
									
										1730
									
								
								block/qcow2.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										162
									
								
								block/qcow2.h
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								block/qcow2.h
									
									
									
									
									
								
							@@ -26,13 +26,13 @@
 | 
				
			|||||||
#define BLOCK_QCOW2_H
 | 
					#define BLOCK_QCOW2_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "aes.h"
 | 
					#include "aes.h"
 | 
				
			||||||
#include "qemu-coroutine.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#define DEBUG_ALLOC
 | 
					//#define DEBUG_ALLOC
 | 
				
			||||||
//#define DEBUG_ALLOC2
 | 
					//#define DEBUG_ALLOC2
 | 
				
			||||||
//#define DEBUG_EXT
 | 
					//#define DEBUG_EXT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
 | 
					#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
 | 
				
			||||||
 | 
					#define QCOW_VERSION 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define QCOW_CRYPT_NONE 0
 | 
					#define QCOW_CRYPT_NONE 0
 | 
				
			||||||
#define QCOW_CRYPT_AES  1
 | 
					#define QCOW_CRYPT_AES  1
 | 
				
			||||||
@@ -43,8 +43,6 @@
 | 
				
			|||||||
#define QCOW_OFLAG_COPIED     (1LL << 63)
 | 
					#define QCOW_OFLAG_COPIED     (1LL << 63)
 | 
				
			||||||
/* indicate that the cluster is compressed (they never have the copied flag) */
 | 
					/* indicate that the cluster is compressed (they never have the copied flag) */
 | 
				
			||||||
#define QCOW_OFLAG_COMPRESSED (1LL << 62)
 | 
					#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 */
 | 
					#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,11 +51,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define L2_CACHE_SIZE 16
 | 
					#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 {
 | 
					typedef struct QCowHeader {
 | 
				
			||||||
    uint32_t magic;
 | 
					    uint32_t magic;
 | 
				
			||||||
    uint32_t version;
 | 
					    uint32_t version;
 | 
				
			||||||
@@ -72,14 +65,6 @@ typedef struct QCowHeader {
 | 
				
			|||||||
    uint32_t refcount_table_clusters;
 | 
					    uint32_t refcount_table_clusters;
 | 
				
			||||||
    uint32_t nb_snapshots;
 | 
					    uint32_t nb_snapshots;
 | 
				
			||||||
    uint64_t snapshots_offset;
 | 
					    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;
 | 
					} QCowHeader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct QCowSnapshot {
 | 
					typedef struct QCowSnapshot {
 | 
				
			||||||
@@ -87,52 +72,14 @@ typedef struct QCowSnapshot {
 | 
				
			|||||||
    uint32_t l1_size;
 | 
					    uint32_t l1_size;
 | 
				
			||||||
    char *id_str;
 | 
					    char *id_str;
 | 
				
			||||||
    char *name;
 | 
					    char *name;
 | 
				
			||||||
    uint64_t disk_size;
 | 
					    uint32_t vm_state_size;
 | 
				
			||||||
    uint64_t vm_state_size;
 | 
					 | 
				
			||||||
    uint32_t date_sec;
 | 
					    uint32_t date_sec;
 | 
				
			||||||
    uint32_t date_nsec;
 | 
					    uint32_t date_nsec;
 | 
				
			||||||
    uint64_t vm_clock_nsec;
 | 
					    uint64_t vm_clock_nsec;
 | 
				
			||||||
} QCowSnapshot;
 | 
					} 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,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Incompatible feature bits */
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
    QCOW2_INCOMPAT_DIRTY_BITNR   = 0,
 | 
					 | 
				
			||||||
    QCOW2_INCOMPAT_DIRTY         = 1 << QCOW2_INCOMPAT_DIRTY_BITNR,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QCOW2_INCOMPAT_MASK          = QCOW2_INCOMPAT_DIRTY,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Compatible feature bits */
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
    QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR = 0,
 | 
					 | 
				
			||||||
    QCOW2_COMPAT_LAZY_REFCOUNTS       = 1 << QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QCOW2_COMPAT_FEAT_MASK            = QCOW2_COMPAT_LAZY_REFCOUNTS,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Qcow2Feature {
 | 
					 | 
				
			||||||
    uint8_t type;
 | 
					 | 
				
			||||||
    uint8_t bit;
 | 
					 | 
				
			||||||
    char    name[46];
 | 
					 | 
				
			||||||
} QEMU_PACKED Qcow2Feature;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct BDRVQcowState {
 | 
					typedef struct BDRVQcowState {
 | 
				
			||||||
 | 
					    BlockDriverState *hd;
 | 
				
			||||||
    int cluster_bits;
 | 
					    int cluster_bits;
 | 
				
			||||||
    int cluster_size;
 | 
					    int cluster_size;
 | 
				
			||||||
    int cluster_sectors;
 | 
					    int cluster_sectors;
 | 
				
			||||||
@@ -145,10 +92,9 @@ typedef struct BDRVQcowState {
 | 
				
			|||||||
    uint64_t cluster_offset_mask;
 | 
					    uint64_t cluster_offset_mask;
 | 
				
			||||||
    uint64_t l1_table_offset;
 | 
					    uint64_t l1_table_offset;
 | 
				
			||||||
    uint64_t *l1_table;
 | 
					    uint64_t *l1_table;
 | 
				
			||||||
 | 
					    uint64_t *l2_cache;
 | 
				
			||||||
    Qcow2Cache* l2_table_cache;
 | 
					    uint64_t l2_cache_offsets[L2_CACHE_SIZE];
 | 
				
			||||||
    Qcow2Cache* refcount_block_cache;
 | 
					    uint32_t l2_cache_counts[L2_CACHE_SIZE];
 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t *cluster_cache;
 | 
					    uint8_t *cluster_cache;
 | 
				
			||||||
    uint8_t *cluster_data;
 | 
					    uint8_t *cluster_data;
 | 
				
			||||||
    uint64_t cluster_cache_offset;
 | 
					    uint64_t cluster_cache_offset;
 | 
				
			||||||
@@ -157,11 +103,11 @@ typedef struct BDRVQcowState {
 | 
				
			|||||||
    uint64_t *refcount_table;
 | 
					    uint64_t *refcount_table;
 | 
				
			||||||
    uint64_t refcount_table_offset;
 | 
					    uint64_t refcount_table_offset;
 | 
				
			||||||
    uint32_t refcount_table_size;
 | 
					    uint32_t refcount_table_size;
 | 
				
			||||||
 | 
					    uint64_t refcount_block_cache_offset;
 | 
				
			||||||
 | 
					    uint16_t *refcount_block_cache;
 | 
				
			||||||
    int64_t free_cluster_index;
 | 
					    int64_t free_cluster_index;
 | 
				
			||||||
    int64_t free_byte_offset;
 | 
					    int64_t free_byte_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CoMutex lock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
 | 
					    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
 | 
				
			||||||
    uint32_t crypt_method_header;
 | 
					    uint32_t crypt_method_header;
 | 
				
			||||||
    AES_KEY aes_encrypt_key;
 | 
					    AES_KEY aes_encrypt_key;
 | 
				
			||||||
@@ -170,17 +116,6 @@ typedef struct BDRVQcowState {
 | 
				
			|||||||
    int snapshots_size;
 | 
					    int snapshots_size;
 | 
				
			||||||
    int nb_snapshots;
 | 
					    int nb_snapshots;
 | 
				
			||||||
    QCowSnapshot *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;
 | 
					} BDRVQcowState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* XXX: use std qcow open function ? */
 | 
					/* XXX: use std qcow open function ? */
 | 
				
			||||||
@@ -201,101 +136,62 @@ typedef struct QCowL2Meta
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    uint64_t offset;
 | 
					    uint64_t offset;
 | 
				
			||||||
    uint64_t cluster_offset;
 | 
					    uint64_t cluster_offset;
 | 
				
			||||||
    uint64_t alloc_offset;
 | 
					 | 
				
			||||||
    int n_start;
 | 
					    int n_start;
 | 
				
			||||||
    int nb_available;
 | 
					    int nb_available;
 | 
				
			||||||
    int nb_clusters;
 | 
					    int nb_clusters;
 | 
				
			||||||
    CoQueue dependent_requests;
 | 
					    struct QCowL2Meta *depends_on;
 | 
				
			||||||
 | 
					    QLIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QLIST_ENTRY(QCowL2Meta) next_in_flight;
 | 
					    QLIST_ENTRY(QCowL2Meta) next_in_flight;
 | 
				
			||||||
} QCowL2Meta;
 | 
					} 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)
 | 
					static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return (size + (s->cluster_size - 1)) >> s->cluster_bits;
 | 
					    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)
 | 
					static inline int64_t align_offset(int64_t offset, int n)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    offset = (offset + n - 1) & ~(n - 1);
 | 
					    offset = (offset + n - 1) & ~(n - 1);
 | 
				
			||||||
    return offset;
 | 
					    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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Check whether refcounts are eager or lazy */
 | 
					 | 
				
			||||||
static inline bool qcow2_need_accurate_refcounts(BDRVQcowState *s)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return !(s->incompatible_features & QCOW2_INCOMPAT_DIRTY);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FIXME Need qcow2_ prefix to global functions
 | 
					// FIXME Need qcow2_ prefix to global functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* qcow2.c functions */
 | 
					/* qcow2.c functions */
 | 
				
			||||||
int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
 | 
					int qcow2_backing_read1(BlockDriverState *bs,
 | 
				
			||||||
                  int64_t sector_num, int nb_sectors);
 | 
					                  int64_t sector_num, uint8_t *buf, int nb_sectors);
 | 
				
			||||||
int qcow2_update_header(BlockDriverState *bs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* qcow2-refcount.c functions */
 | 
					/* qcow2-refcount.c functions */
 | 
				
			||||||
int qcow2_refcount_init(BlockDriverState *bs);
 | 
					int qcow2_refcount_init(BlockDriverState *bs);
 | 
				
			||||||
void qcow2_refcount_close(BlockDriverState *bs);
 | 
					void qcow2_refcount_close(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
 | 
					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);
 | 
					int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
 | 
				
			||||||
void qcow2_free_clusters(BlockDriverState *bs,
 | 
					void qcow2_free_clusters(BlockDriverState *bs,
 | 
				
			||||||
    int64_t offset, int64_t size);
 | 
					    int64_t offset, int64_t size);
 | 
				
			||||||
void qcow2_free_any_clusters(BlockDriverState *bs,
 | 
					void qcow2_free_any_clusters(BlockDriverState *bs,
 | 
				
			||||||
    uint64_t cluster_offset, int nb_clusters);
 | 
					    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,
 | 
					int qcow2_update_snapshot_refcount(BlockDriverState *bs,
 | 
				
			||||||
    int64_t l1_table_offset, int l1_size, int addend);
 | 
					    int64_t l1_table_offset, int l1_size, int addend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
 | 
					int qcow2_check_refcounts(BlockDriverState *bs);
 | 
				
			||||||
                          BdrvCheckMode fix);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* qcow2-cluster.c functions */
 | 
					/* 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);
 | 
					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,
 | 
					void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
 | 
				
			||||||
                     uint8_t *out_buf, const uint8_t *in_buf,
 | 
					                     uint8_t *out_buf, const uint8_t *in_buf,
 | 
				
			||||||
                     int nb_sectors, int enc,
 | 
					                     int nb_sectors, int enc,
 | 
				
			||||||
                     const AES_KEY *key);
 | 
					                     const AES_KEY *key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
					uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
				
			||||||
    int *num, uint64_t *cluster_offset);
 | 
					    int *num);
 | 
				
			||||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
					int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
 | 
				
			||||||
    int n_start, int n_end, int *num, QCowL2Meta *m);
 | 
					    int n_start, int n_end, int *num, QCowL2Meta *m);
 | 
				
			||||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 | 
					uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 | 
				
			||||||
@@ -303,34 +199,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
 | 
				
			|||||||
                                         int compressed_size);
 | 
					                                         int compressed_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
 | 
					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 */
 | 
					/* qcow2-snapshot.c functions */
 | 
				
			||||||
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
 | 
					int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
 | 
				
			||||||
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
 | 
					int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
 | 
				
			||||||
int qcow2_snapshot_delete(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_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
 | 
				
			||||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void qcow2_free_snapshots(BlockDriverState *bs);
 | 
					void qcow2_free_snapshots(BlockDriverState *bs);
 | 
				
			||||||
int qcow2_read_snapshots(BlockDriverState *bs);
 | 
					int qcow2_read_snapshots(BlockDriverState *bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* qcow2-cache.c functions */
 | 
					 | 
				
			||||||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
 | 
					 | 
				
			||||||
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,248 +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;
 | 
					 | 
				
			||||||
                check->result->corruptions_fixed++;
 | 
					 | 
				
			||||||
            } 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;
 | 
					 | 
				
			||||||
                check->result->corruptions_fixed++;
 | 
					 | 
				
			||||||
            } 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++;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Mark an image clean once it passes check or has been repaired
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /* Skip if there were unfixable corruptions or I/O errors */
 | 
					 | 
				
			||||||
    if (result->corruptions > 0 || result->check_errors > 0) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Skip if image is already marked clean */
 | 
					 | 
				
			||||||
    if (!(s->header.features & QED_F_NEED_CHECK)) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Ensure fixes reach storage before clearing check bit */
 | 
					 | 
				
			||||||
    bdrv_flush(s->bs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    s->header.features &= ~QED_F_NEED_CHECK;
 | 
					 | 
				
			||||||
    qed_write_header_sync(s);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (fix) {
 | 
					 | 
				
			||||||
            qed_check_mark_clean(s, result);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										1575
									
								
								block/qed.c
									
									
									
									
									
								
							
							
						
						
									
										1575
									
								
								block/qed.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										344
									
								
								block/qed.h
									
									
									
									
									
								
							
							
						
						
									
										344
									
								
								block/qed.h
									
									
									
									
									
								
							@@ -1,344 +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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Header functions
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int qed_write_header_sync(BDRVQEDState *s);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * 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
 | 
					 * This work is licensed under the terms of the GNU GPL, version 2.  See
 | 
				
			||||||
 * the COPYING file in the top-level directory.
 | 
					 * 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
 | 
					#ifndef QEMU_RAW_POSIX_AIO_H
 | 
				
			||||||
#define 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)
 | 
					int qemu_ftruncate64(int fd, int64_t length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    LARGE_INTEGER li;
 | 
					    LARGE_INTEGER li;
 | 
				
			||||||
    DWORD dw;
 | 
					 | 
				
			||||||
    LONG high;
 | 
					    LONG high;
 | 
				
			||||||
    HANDLE h;
 | 
					    HANDLE h;
 | 
				
			||||||
    BOOL res;
 | 
					    BOOL res;
 | 
				
			||||||
@@ -54,15 +53,12 @@ int qemu_ftruncate64(int fd, int64_t length)
 | 
				
			|||||||
    /* get current position, ftruncate do not change position */
 | 
					    /* get current position, ftruncate do not change position */
 | 
				
			||||||
    li.HighPart = 0;
 | 
					    li.HighPart = 0;
 | 
				
			||||||
    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
 | 
					    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;
 | 
						return -1;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    high = length >> 32;
 | 
					    high = length >> 32;
 | 
				
			||||||
    dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN);
 | 
					    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
 | 
				
			||||||
    if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
 | 
					 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    res = SetEndOfFile(h);
 | 
					    res = SetEndOfFile(h);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* back to old position */
 | 
					    /* 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)
 | 
					static int raw_open(BlockDriverState *bs, const char *filename, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVRawState *s = bs->opaque;
 | 
					    BDRVRawState *s = bs->opaque;
 | 
				
			||||||
    int access_flags;
 | 
					    int access_flags, create_flags;
 | 
				
			||||||
    DWORD overlapped;
 | 
					    DWORD overlapped;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->type = FTYPE_FILE;
 | 
					    s->type = FTYPE_FILE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (flags & BDRV_O_RDWR) {
 | 
					    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
 | 
				
			||||||
        access_flags = GENERIC_READ | GENERIC_WRITE;
 | 
					        access_flags = GENERIC_READ | GENERIC_WRITE;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        access_flags = GENERIC_READ;
 | 
					        access_flags = GENERIC_READ;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (flags & BDRV_O_CREAT) {
 | 
				
			||||||
 | 
					        create_flags = CREATE_ALWAYS;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        create_flags = OPEN_EXISTING;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    overlapped = FILE_ATTRIBUTE_NORMAL;
 | 
					    overlapped = FILE_ATTRIBUTE_NORMAL;
 | 
				
			||||||
    if (flags & BDRV_O_NOCACHE)
 | 
					    if ((flags & BDRV_O_NOCACHE))
 | 
				
			||||||
        overlapped |= FILE_FLAG_NO_BUFFERING;
 | 
					        overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
 | 
				
			||||||
    if (!(flags & BDRV_O_CACHE_WB))
 | 
					    else if (!(flags & BDRV_O_CACHE_WB))
 | 
				
			||||||
        overlapped |= FILE_FLAG_WRITE_THROUGH;
 | 
					        overlapped |= FILE_FLAG_WRITE_THROUGH;
 | 
				
			||||||
    s->hfile = CreateFile(filename, access_flags,
 | 
					    s->hfile = CreateFile(filename, access_flags,
 | 
				
			||||||
                          FILE_SHARE_READ, NULL,
 | 
					                          FILE_SHARE_READ, NULL,
 | 
				
			||||||
                          OPEN_EXISTING, overlapped, NULL);
 | 
					                          create_flags, overlapped, NULL);
 | 
				
			||||||
    if (s->hfile == INVALID_HANDLE_VALUE) {
 | 
					    if (s->hfile == INVALID_HANDLE_VALUE) {
 | 
				
			||||||
        int err = GetLastError();
 | 
					        int err = GetLastError();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -151,17 +151,10 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
 | 
				
			|||||||
    return ret_count;
 | 
					    return ret_count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int raw_flush(BlockDriverState *bs)
 | 
					static void raw_flush(BlockDriverState *bs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    BDRVRawState *s = bs->opaque;
 | 
					    BDRVRawState *s = bs->opaque;
 | 
				
			||||||
    int ret;
 | 
					    FlushFileBuffers(s->hfile);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret = FlushFileBuffers(s->hfile);
 | 
					 | 
				
			||||||
    if (ret == 0) {
 | 
					 | 
				
			||||||
        return -EIO;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raw_close(BlockDriverState *bs)
 | 
					static void raw_close(BlockDriverState *bs)
 | 
				
			||||||
@@ -217,31 +210,6 @@ static int64_t raw_getlength(BlockDriverState *bs)
 | 
				
			|||||||
    return l.QuadPart;
 | 
					    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)
 | 
					static int raw_create(const char *filename, QEMUOptionParameter *options)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int fd;
 | 
					    int fd;
 | 
				
			||||||
@@ -255,13 +223,13 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
 | 
				
			|||||||
        options++;
 | 
					        options++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
 | 
					    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
 | 
				
			||||||
                   0644);
 | 
					              0644);
 | 
				
			||||||
    if (fd < 0)
 | 
					    if (fd < 0)
 | 
				
			||||||
        return -EIO;
 | 
					        return -EIO;
 | 
				
			||||||
    set_sparse(fd);
 | 
					    set_sparse(fd);
 | 
				
			||||||
    ftruncate(fd, total_size * 512);
 | 
					    ftruncate(fd, total_size * 512);
 | 
				
			||||||
    qemu_close(fd);
 | 
					    close(fd);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -274,22 +242,17 @@ static QEMUOptionParameter raw_create_options[] = {
 | 
				
			|||||||
    { NULL }
 | 
					    { NULL }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BlockDriver bdrv_file = {
 | 
					static BlockDriver bdrv_raw = {
 | 
				
			||||||
    .format_name	= "file",
 | 
					    .format_name	= "raw",
 | 
				
			||||||
    .protocol_name	= "file",
 | 
					 | 
				
			||||||
    .instance_size	= sizeof(BDRVRawState),
 | 
					    .instance_size	= sizeof(BDRVRawState),
 | 
				
			||||||
    .bdrv_file_open	= raw_open,
 | 
					    .bdrv_open		= raw_open,
 | 
				
			||||||
    .bdrv_close		= raw_close,
 | 
					    .bdrv_close		= raw_close,
 | 
				
			||||||
    .bdrv_create	= raw_create,
 | 
					    .bdrv_create	= raw_create,
 | 
				
			||||||
 | 
					    .bdrv_flush		= raw_flush,
 | 
				
			||||||
    .bdrv_read              = raw_read,
 | 
					    .bdrv_read		= raw_read,
 | 
				
			||||||
    .bdrv_write             = raw_write,
 | 
					    .bdrv_write		= raw_write,
 | 
				
			||||||
    .bdrv_co_flush_to_disk  = raw_flush,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .bdrv_truncate	= raw_truncate,
 | 
					    .bdrv_truncate	= raw_truncate,
 | 
				
			||||||
    .bdrv_getlength	= raw_getlength,
 | 
					    .bdrv_getlength	= raw_getlength,
 | 
				
			||||||
    .bdrv_get_allocated_file_size
 | 
					 | 
				
			||||||
                        = raw_get_allocated_file_size,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .create_options = raw_create_options,
 | 
					    .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);
 | 
					    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;
 | 
					        access_flags = GENERIC_READ | GENERIC_WRITE;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        access_flags = GENERIC_READ;
 | 
					        access_flags = GENERIC_READ;
 | 
				
			||||||
@@ -382,9 +345,9 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 | 
				
			|||||||
    create_flags = OPEN_EXISTING;
 | 
					    create_flags = OPEN_EXISTING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    overlapped = FILE_ATTRIBUTE_NORMAL;
 | 
					    overlapped = FILE_ATTRIBUTE_NORMAL;
 | 
				
			||||||
    if (flags & BDRV_O_NOCACHE)
 | 
					    if ((flags & BDRV_O_NOCACHE))
 | 
				
			||||||
        overlapped |= FILE_FLAG_NO_BUFFERING;
 | 
					        overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
 | 
				
			||||||
    if (!(flags & BDRV_O_CACHE_WB))
 | 
					    else if (!(flags & BDRV_O_CACHE_WB))
 | 
				
			||||||
        overlapped |= FILE_FLAG_WRITE_THROUGH;
 | 
					        overlapped |= FILE_FLAG_WRITE_THROUGH;
 | 
				
			||||||
    s->hfile = CreateFile(filename, access_flags,
 | 
					    s->hfile = CreateFile(filename, access_flags,
 | 
				
			||||||
                          FILE_SHARE_READ, NULL,
 | 
					                          FILE_SHARE_READ, NULL,
 | 
				
			||||||
@@ -399,33 +362,58 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 | 
				
			|||||||
    return 0;
 | 
					    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 = {
 | 
					static BlockDriver bdrv_host_device = {
 | 
				
			||||||
    .format_name	= "host_device",
 | 
					    .format_name	= "host_device",
 | 
				
			||||||
    .protocol_name	= "host_device",
 | 
					 | 
				
			||||||
    .instance_size	= sizeof(BDRVRawState),
 | 
					    .instance_size	= sizeof(BDRVRawState),
 | 
				
			||||||
    .bdrv_probe_device	= hdev_probe_device,
 | 
					    .bdrv_probe_device	= hdev_probe_device,
 | 
				
			||||||
    .bdrv_file_open	= hdev_open,
 | 
					    .bdrv_open		= hdev_open,
 | 
				
			||||||
    .bdrv_close		= raw_close,
 | 
					    .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_read		= raw_read,
 | 
				
			||||||
 | 
					    .bdrv_write	        = raw_write,
 | 
				
			||||||
    .bdrv_getlength	= raw_getlength,
 | 
					    .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);
 | 
					    bdrv_register(&bdrv_host_device);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block_init(bdrv_file_init);
 | 
					block_init(bdrv_raw_init);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										145
									
								
								block/raw.c
									
									
									
									
									
								
							
							
						
						
									
										145
									
								
								block/raw.c
									
									
									
									
									
								
							@@ -1,145 +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)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
 | 
					 | 
				
			||||||
    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)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
 | 
					 | 
				
			||||||
    return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void raw_close(BlockDriverState *bs)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
 | 
					 | 
				
			||||||
                                            int64_t sector_num,
 | 
					 | 
				
			||||||
                                            int nb_sectors, int *pnum)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return bdrv_co_is_allocated(bs->file, sector_num, nb_sectors, pnum);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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_is_allocated   = raw_co_is_allocated,
 | 
					 | 
				
			||||||
    .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);
 | 
					 | 
				
			||||||
							
								
								
									
										970
									
								
								block/rbd.c
									
									
									
									
									
								
							
							
						
						
									
										970
									
								
								block/rbd.c
									
									
									
									
									
								
							@@ -1,970 +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 "\".
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* rbd_aio_discard added in 0.1.2 */
 | 
					 | 
				
			||||||
#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 2)
 | 
					 | 
				
			||||||
#define LIBRBD_SUPPORTS_DISCARD
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#undef LIBRBD_SUPPORTS_DISCARD
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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 enum {
 | 
					 | 
				
			||||||
    RBD_AIO_READ,
 | 
					 | 
				
			||||||
    RBD_AIO_WRITE,
 | 
					 | 
				
			||||||
    RBD_AIO_DISCARD
 | 
					 | 
				
			||||||
} RBDAIOCmd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct RBDAIOCB {
 | 
					 | 
				
			||||||
    BlockDriverAIOCB common;
 | 
					 | 
				
			||||||
    QEMUBH *bh;
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
    QEMUIOVector *qiov;
 | 
					 | 
				
			||||||
    char *bounce;
 | 
					 | 
				
			||||||
    RBDAIOCmd cmd;
 | 
					 | 
				
			||||||
    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->cmd == RBD_AIO_WRITE ||
 | 
					 | 
				
			||||||
        acb->cmd == RBD_AIO_DISCARD) {
 | 
					 | 
				
			||||||
        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);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
     * Fallback to more conservative semantics if setting cache
 | 
					 | 
				
			||||||
     * options fails. Ignore errors from setting rbd_cache because the
 | 
					 | 
				
			||||||
     * only possible error is that the option does not exist, and
 | 
					 | 
				
			||||||
     * librbd defaults to no caching. If write through caching cannot
 | 
					 | 
				
			||||||
     * be set up, fall back to no caching.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    if (flags & BDRV_O_NOCACHE) {
 | 
					 | 
				
			||||||
        rados_conf_set(s->cluster, "rbd_cache", "false");
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        rados_conf_set(s->cluster, "rbd_cache", "true");
 | 
					 | 
				
			||||||
        if (!(flags & BDRV_O_CACHE_WB)) {
 | 
					 | 
				
			||||||
            r = rados_conf_set(s->cluster, "rbd_cache_max_dirty", "0");
 | 
					 | 
				
			||||||
            if (r < 0) {
 | 
					 | 
				
			||||||
                rados_conf_set(s->cluster, "rbd_cache", "false");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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->cmd == RBD_AIO_READ) {
 | 
					 | 
				
			||||||
        qemu_iovec_from_buf(acb->qiov, 0, 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 int rbd_aio_discard_wrapper(rbd_image_t image,
 | 
					 | 
				
			||||||
                                   uint64_t off,
 | 
					 | 
				
			||||||
                                   uint64_t len,
 | 
					 | 
				
			||||||
                                   rbd_completion_t comp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#ifdef LIBRBD_SUPPORTS_DISCARD
 | 
					 | 
				
			||||||
    return rbd_aio_discard(image, off, len, comp);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    return -ENOTSUP;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
 | 
					 | 
				
			||||||
                                       int64_t sector_num,
 | 
					 | 
				
			||||||
                                       QEMUIOVector *qiov,
 | 
					 | 
				
			||||||
                                       int nb_sectors,
 | 
					 | 
				
			||||||
                                       BlockDriverCompletionFunc *cb,
 | 
					 | 
				
			||||||
                                       void *opaque,
 | 
					 | 
				
			||||||
                                       RBDAIOCmd cmd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    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->cmd = cmd;
 | 
					 | 
				
			||||||
    acb->qiov = qiov;
 | 
					 | 
				
			||||||
    if (cmd == RBD_AIO_DISCARD) {
 | 
					 | 
				
			||||||
        acb->bounce = NULL;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        acb->bounce = qemu_blockalign(bs, qiov->size);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    acb->ret = 0;
 | 
					 | 
				
			||||||
    acb->error = 0;
 | 
					 | 
				
			||||||
    acb->s = s;
 | 
					 | 
				
			||||||
    acb->cancelled = 0;
 | 
					 | 
				
			||||||
    acb->bh = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (cmd == RBD_AIO_WRITE) {
 | 
					 | 
				
			||||||
        qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch (cmd) {
 | 
					 | 
				
			||||||
    case RBD_AIO_WRITE:
 | 
					 | 
				
			||||||
        r = rbd_aio_write(s->image, off, size, buf, c);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case RBD_AIO_READ:
 | 
					 | 
				
			||||||
        r = rbd_aio_read(s->image, off, size, buf, c);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case RBD_AIO_DISCARD:
 | 
					 | 
				
			||||||
        r = rbd_aio_discard_wrapper(s->image, off, size, c);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
        r = -EINVAL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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_start_aio(bs, sector_num, qiov, nb_sectors, cb, opaque,
 | 
					 | 
				
			||||||
                         RBD_AIO_READ);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
 | 
					 | 
				
			||||||
                                             int64_t sector_num,
 | 
					 | 
				
			||||||
                                             QEMUIOVector *qiov,
 | 
					 | 
				
			||||||
                                             int nb_sectors,
 | 
					 | 
				
			||||||
                                             BlockDriverCompletionFunc *cb,
 | 
					 | 
				
			||||||
                                             void *opaque)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return rbd_start_aio(bs, sector_num, qiov, nb_sectors, cb, opaque,
 | 
					 | 
				
			||||||
                         RBD_AIO_WRITE);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef LIBRBD_SUPPORTS_DISCARD
 | 
					 | 
				
			||||||
static BlockDriverAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs,
 | 
					 | 
				
			||||||
                                              int64_t sector_num,
 | 
					 | 
				
			||||||
                                              int nb_sectors,
 | 
					 | 
				
			||||||
                                              BlockDriverCompletionFunc *cb,
 | 
					 | 
				
			||||||
                                              void *opaque)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return rbd_start_aio(bs, sector_num, NULL, nb_sectors, cb, opaque,
 | 
					 | 
				
			||||||
                         RBD_AIO_DISCARD);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef LIBRBD_SUPPORTS_DISCARD
 | 
					 | 
				
			||||||
    .bdrv_aio_discard       = qemu_rbd_aio_discard,
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .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);
 | 
					 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user