mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-29 16:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			1245 Commits
		
	
	
		
			dev-mcsont
			...
			old-v1_00_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 9812657777 | ||
|  | 0b09312fc6 | ||
|  | d0a7ac6b74 | ||
|  | ff9a238fbd | ||
|  | 359fffa5f1 | ||
|  | 5bf92ced1a | ||
|  | 340bcc7b45 | ||
|  | ef03742bd4 | ||
|  | 20431ec16d | ||
|  | becba8157b | ||
|  | 51fd3bb0eb | ||
|  | 4bbd3acb4e | ||
|  | 3bc930ea7b | ||
|  | d1b26f8e86 | ||
|  | fdf15caaff | ||
|  | c7b4a53c0b | ||
|  | af78dc0308 | ||
|  | 5ad39493c4 | ||
|  | 61f597b408 | ||
|  | 2162825240 | ||
|  | 2b780e70d1 | ||
|  | a3823f818e | ||
|  | 1f7c47bcaf | ||
|  | ec53c365a2 | ||
|  | 793ad1f2d4 | ||
|  | 9bc733b76c | ||
|  | 21b28f0217 | ||
|  | d3e23caa52 | ||
|  | 9e7518de67 | ||
|  | 679f0047aa | ||
|  | d77d5ce14b | ||
|  | 33ec22a2af | ||
|  | 353053225f | ||
|  | b7f3d6f7f7 | ||
|  | e34577499d | ||
|  | 4cf8960c0c | ||
|  | 1f93ea0675 | ||
|  | 25b705c3a8 | ||
|  | 0725588731 | ||
|  | fc5c61cc8b | ||
|  | ac282e63c6 | ||
|  | c3941941ce | ||
|  | 46cdd53323 | ||
|  | 3ff3e302c3 | ||
|  | f2ceecf95c | ||
|  | 9314c7c881 | ||
|  | 54abb2c572 | ||
|  | 8fa3bdd025 | ||
|  | 5e7a308528 | ||
|  | 7952177786 | ||
|  | 9afbe49c84 | ||
|  | 9f06ba2db3 | ||
|  | fe55bfddcf | ||
|  | c0842e6444 | ||
|  | 3fed20d06a | ||
|  | 5e8f2e2c04 | ||
|  | e4df99ea84 | ||
|  | b3276f5f11 | ||
|  | 32667ca256 | ||
|  | bed122a170 | ||
|  | 14adc9b875 | ||
|  | a8778bbc5a | ||
|  | a54e641f44 | ||
|  | 5c99efe87a | ||
|  | 7da1d731ff | ||
|  | af9828e819 | ||
|  | 7a27136142 | ||
|  | 012ad2d423 | ||
|  | ef3bdbf4da | ||
|  | b3bb698f7b | ||
|  | 1ed5d1e4c1 | ||
|  | bdee01a03d | ||
|  | 458f7376d7 | ||
|  | cb3a00e027 | ||
|  | 482eb1f3fb | ||
|  | 6e0f638f5e | ||
|  | bab349047d | ||
|  | 28ea6b8de8 | ||
|  | 9d51bbdae8 | ||
|  | d622f79533 | ||
|  | 04c8515ad1 | ||
|  | 53bc4251d1 | ||
|  | a5a751f02f | ||
|  | 66ed5f82c4 | ||
|  | c802a9e6aa | ||
|  | 880f210946 | ||
|  | 4f9f7eb6a6 | ||
|  | f910c4a8e7 | ||
|  | 529686d965 | ||
|  | 84dfd1536f | ||
|  | 85dedc324c | ||
|  | d639237411 | ||
|  | 449aaf75f1 | ||
|  | b1fda66caa | ||
|  | 66a8e90fd9 | ||
|  | 37b487d191 | ||
|  | 6c59fe3577 | ||
|  | 1cbb70c992 | ||
|  | e06b39f882 | ||
|  | 2602b1493e | ||
|  | 989d14502d | ||
|  | f78a550282 | ||
|  | 54a1abb284 | ||
|  | 97b492a8e2 | ||
|  | 0873bd14a9 | ||
|  | eff6ba429a | ||
|  | 8c18064be4 | ||
|  | 44a1ac0cf3 | ||
|  | 28dc8d88dd | ||
|  | 2c0c2b64ba | ||
|  | bd3e0f5248 | ||
|  | cd52d98938 | ||
|  | 894c70e7f8 | ||
|  | 51d70c2edd | ||
|  | 7d4b355240 | ||
|  | 3b56193b98 | ||
|  | b16045b57d | ||
|  | 9e8b0fca5b | ||
|  | 35cf1b3b5b | ||
|  | 83f788af57 | ||
|  | 2ffe378d3f | ||
|  | 38b33a4a5e | ||
|  | 60bf9ed0a0 | ||
|  | 16adf4de1b | ||
|  | 80de983023 | ||
|  | 8703ca623f | ||
|  | 286253a73f | ||
|  | bd806a41df | ||
|  | b89c4e9002 | ||
|  | 6dbf31c0c3 | ||
|  | 060c45d8a1 | ||
|  | 33d3e82e4d | ||
|  | 4bb074514d | ||
|  | e3f8892003 | ||
|  | 9d00ad5f18 | ||
|  | dae4344850 | ||
|  | aa7f3fabe2 | ||
|  | f93434a8ce | ||
|  | 25dee56be9 | ||
|  | ce9a3f3797 | ||
|  | 11e384920a | ||
|  | a0a1f1e536 | ||
|  | 3b3d0ea9eb | ||
|  | 2f4d78286d | ||
|  | 677dc6f985 | ||
|  | d52057e732 | ||
|  | fa2a1cb1fb | ||
|  | 19a0fb04ad | ||
|  | 947352f2fe | ||
|  | adcbedb686 | ||
|  | 7732f92acd | ||
|  | ad8a001688 | ||
|  | 9121eada08 | ||
|  | 49bd4d25a2 | ||
|  | d80b4129c6 | ||
|  | 7edb4172d5 | ||
|  | c3a4677990 | ||
|  | 5cbb893a3b | ||
|  | f28a2a432b | ||
|  | 03b75a2d27 | ||
|  | 859fe69083 | ||
|  | f6f2205ddb | ||
|  | 0f9a03ef61 | ||
|  | 9aa417c084 | ||
|  | 7b70952f5d | ||
|  | edd3d07b49 | ||
|  | 5293d0a4ec | ||
|  | 3c8c7beae1 | ||
|  | 9c3ba9fdcd | ||
|  | fb1748fb0f | ||
|  | 0a109fbd03 | ||
|  | 5cf64db74e | ||
|  | 488cc94f36 | ||
|  | e15846bf79 | ||
|  | 752bd00674 | ||
|  | 7fadfcbe32 | ||
|  | 41141e75bb | ||
|  | 50f641e627 | ||
|  | c7883fd093 | ||
|  | 4fcb24b2b1 | ||
|  | 5003557935 | ||
|  | bdf1ba84da | ||
|  | b0b4def983 | ||
|  | cc184bbe9e | ||
|  | ad30c830aa | ||
|  | 1d791a8af4 | ||
|  | e63c51cd97 | ||
|  | f202e32908 | ||
|  | 26e1a08e82 | ||
|  | 4d5119d435 | ||
|  | 75e34ea62e | ||
|  | 0a183d6274 | ||
|  | 21d8060aea | ||
|  | 9cbe906f60 | ||
|  | 8ce4137399 | ||
|  | 5f8a139347 | ||
|  | 9bb009a3fe | ||
|  | 726d65923f | ||
|  | 8a6be4cb2d | ||
|  | 10b06beb8e | ||
|  | 81318c7968 | ||
|  | 47a2c1c6e5 | ||
|  | 39cee65c6b | ||
|  | 8582ec724e | ||
|  | b0139682e8 | ||
|  | d39c475a6d | ||
|  | 48f38354c6 | ||
|  | cd5a920ed5 | ||
|  | 71bc1f378d | ||
|  | 0ee6c31cff | ||
|  | af89a9971e | ||
|  | c718a8ef72 | ||
|  | 8c8ad0faf0 | ||
|  | 314d5bbb7f | ||
|  | 102255757a | ||
|  | 914067a0d0 | ||
|  | 06e3ae2536 | ||
|  | 7f9b252556 | ||
|  | 3d700e243f | ||
|  | bcfc78ce11 | ||
|  | 09241765d5 | ||
|  | 671c83c265 | ||
|  | 772d28b766 | ||
|  | c26fcea58d | ||
|  | 1e5e26dbff | ||
|  | 742fc54864 | ||
|  | 49738f43c0 | ||
|  | 9f85f61010 | ||
|  | 239f422039 | ||
|  | 67af3c37be | ||
|  | a9442385c4 | ||
|  | 8c9cd10b8b | ||
|  | 72542059dd | ||
|  | a843fc6d40 | ||
|  | 4beed60c08 | ||
|  | 4049c1e480 | ||
|  | 8449314da2 | ||
|  | 63ad057028 | ||
|  | e720464330 | ||
|  | 24036afef9 | ||
|  | c78fa1a1bc | ||
|  | faa8b9022c | ||
|  | 729bafef7a | ||
|  | 590b028632 | ||
|  | 8150d00f36 | ||
|  | 060065926f | ||
|  | 70babe8a28 | ||
|  | c36e09664f | ||
|  | a9672246f3 | ||
|  | ff571884e9 | ||
|  | 475138bceb | ||
|  | 4a8af199c2 | ||
|  | bdabf5db72 | ||
|  | 6a5f21b34e | ||
|  | d608be103c | ||
|  | 374bb5d18a | ||
|  | 031d6c25ff | ||
|  | 223fb7b075 | ||
|  | a746741971 | ||
|  | 120faf2a58 | ||
|  | 990bca0dc6 | ||
|  | 3406472db7 | ||
|  | 1bd733c9f6 | ||
|  | 238c7f982e | ||
|  | fcb81147cb | ||
|  | 1915b73783 | ||
|  | ee79e621fb | ||
|  | d203275a3b | ||
|  | 9e8a996222 | ||
|  | 0126b0b3ed | ||
|  | 458928612c | ||
|  | e33f88e28d | ||
|  | be570bbf9e | ||
|  | f59b4be110 | ||
|  | 37336e41be | ||
|  | d24a1a3f0a | ||
|  | f7258955bd | ||
|  | 2a1eae5d6f | ||
|  | 50ee0a4adb | ||
|  | 955a26584e | ||
|  | 1d3e407c8f | ||
|  | cb809c4596 | ||
|  | 53bbe2888e | ||
|  | 7246f476a5 | ||
|  | 0785d1c390 | ||
|  | 85d2c49d14 | ||
|  | 8b77d62b7f | ||
|  | 373058a32a | ||
|  | e6293c2c8c | ||
|  | eff181c959 | ||
|  | 54752c2305 | ||
|  | b4753c044f | ||
|  | 26493424ae | ||
|  | 0282fd1332 | ||
|  | b9a019a08b | ||
|  | 66f6a0e687 | ||
|  | 2dd1b9f97d | ||
|  | 89615f3045 | ||
|  | 7e46192f67 | ||
|  | e78d985cdf | ||
|  | e8c4bf56fe | ||
|  | e6aa7d323d | ||
|  | fca8e25929 | ||
|  | 8e8ac286b4 | ||
|  | 7d9770b9a2 | ||
|  | 1996230460 | ||
|  | de7897a864 | ||
|  | e2884dcdb7 | ||
|  | 544a53a42b | ||
|  | 2e4787bfc8 | ||
|  | 1829eeb171 | ||
|  | c7488e3c4a | ||
|  | 3bf9606383 | ||
|  | 4f43f18f0a | ||
|  | 5b7f197397 | ||
|  | 018141c97f | ||
|  | 4d7813e57c | ||
|  | 605c60208f | ||
|  | 884fafcc30 | ||
|  | 56baa90320 | ||
|  | 6bb20ee09e | ||
|  | 541356430c | ||
|  | 2f4d91fd69 | ||
|  | f58c5e6b30 | ||
|  | 0311d0132c | ||
|  | c946c97402 | ||
|  | 84a6f51318 | ||
|  | 24a1501b0d | ||
|  | 383b6f5fcc | ||
|  | 633dd7ff9b | ||
|  | 580624fad6 | ||
|  | a8190f7efa | ||
|  | dd2157534b | ||
|  | 38a90e7669 | ||
|  | 6bfc526dcd | ||
|  | aadb8a7405 | ||
|  | 27082bf77e | ||
|  | a2903c80cd | ||
|  | 9a77c5369c | ||
|  | 3c30741a19 | ||
|  | 7028ad4ec0 | ||
|  | 8de750c6aa | ||
|  | 04f98de9ee | ||
|  | a1a019784b | ||
|  | 4aeeae77bd | ||
|  | 651cfc2b78 | ||
|  | 2ef8af25e2 | ||
|  | 0b13852a5b | ||
|  | 13427578c9 | ||
|  | d89ca2087e | ||
|  | 8b0ea9fba6 | ||
|  | 9f0b653d5a | ||
|  | 659a339233 | ||
|  | 4c29f177a0 | ||
|  | d664e63d55 | ||
|  | 2493509dbe | ||
|  | 1c8b27f554 | ||
|  | 68297b7186 | ||
|  | 34dd8d0a91 | ||
|  | 81c44790d5 | ||
|  | d557b335cf | ||
|  | e2adc28cff | ||
|  | 0fef6a6ecc | ||
|  | f2fd4b8a1f | ||
|  | 95bd5605a8 | ||
|  | 497cca7eca | ||
|  | 54f78feedd | ||
|  | 76408e53ae | ||
|  | be19e74d30 | ||
|  | dac578a775 | ||
|  | 04732ce74b | ||
|  | a6c95a2374 | ||
|  | f68622abe9 | ||
|  | 83a9a7bdb2 | ||
|  | 6500afc0ca | ||
|  | c69b7ecc96 | ||
|  | 615ef1e2d2 | ||
|  | cf69a0cd7f | ||
|  | 06e892fb33 | ||
|  | e6c5dd6865 | ||
|  | 247efdebdb | ||
|  | 76f3792287 | ||
|  | 64d8e2c727 | ||
|  | ead0bd9cb0 | ||
|  | 66fc13b2ec | ||
|  | f3af4128b0 | ||
|  | 0e43107c87 | ||
|  | 1ee3e7997e | ||
|  | 50fd61d91f | ||
|  | e4cdc051a9 | ||
|  | 778e846e96 | ||
|  | a27759b647 | ||
|  | b75eceab41 | ||
|  | e748a5d5f4 | ||
|  | 99c5a3ae46 | ||
|  | 51da710f5a | ||
|  | 569d69b3d2 | ||
|  | 059a6b1d90 | ||
|  | 990af7548a | ||
|  | a38aefdfc8 | ||
|  | 3bcb12e7d1 | ||
|  | 7904ecb462 | ||
|  | 9ba4d45109 | ||
|  | 56b8afe19d | ||
|  | f7aed9a94c | ||
|  | e12a7e881d | ||
|  | 5afb65325d | ||
|  | 135f520f32 | ||
|  | bc251f4ff6 | ||
|  | b8769751f6 | ||
|  | eff96d839e | ||
|  | aa34c23807 | ||
|  | 195acdac8c | ||
|  | 903e03c56c | ||
|  | 0892767b8a | ||
|  | 83ebfa772c | ||
|  | 1583641322 | ||
|  | 9510e2c256 | ||
|  | a9dbabe07e | ||
|  | 12884008fa | ||
|  | 02543bad1c | ||
|  | a8c56a5251 | ||
|  | 4e5a855f3f | ||
|  | 7e497a951e | ||
|  | cd08eabbfa | ||
|  | f7e62d9f81 | ||
|  | 9a3761e86e | ||
|  | 3619a68693 | ||
|  | efaf3c3bf9 | ||
|  | 0e4e6a6f67 | ||
|  | 42458e6278 | ||
|  | 41ec995377 | ||
|  | 4f37599326 | ||
|  | 4144520e5c | ||
|  | 6c4800546c | ||
|  | 733733c8a7 | ||
|  | 2aa67cc946 | ||
|  | 9385981a9d | ||
|  | fff780035d | ||
|  | 46127e673d | ||
|  | 70df59b224 | ||
|  | 0fdbaa803f | ||
|  | 6af1830eff | ||
|  | 6f860e2bd5 | ||
|  | 20a492f7ee | ||
|  | 63875e7591 | ||
|  | 0ad98cabde | ||
|  | 668879d2e1 | ||
|  | 2e09783302 | ||
|  | 49734114b3 | ||
|  | 950d9d6ee7 | ||
|  | f7974aee2e | ||
|  | c870a82621 | ||
|  | 984929a001 | ||
|  | 7f9e2c1db8 | ||
|  | 324e8389dc | ||
|  | 6f448c5a38 | ||
|  | ec43efbb20 | ||
|  | 3ed065de37 | ||
|  | 8152f0d72c | ||
|  | f8047f4736 | ||
|  | b93c66dc2d | ||
|  | ac877b3065 | ||
|  | dee8abfdde | ||
|  | cef3841d73 | ||
|  | 3cd5e8a041 | ||
|  | 515b5f866e | ||
|  | 321f62bf92 | ||
|  | f94fa47b52 | ||
|  | c502f8a722 | ||
|  | 59b4868ac3 | ||
|  | 3634e12cce | ||
|  | 6d45445391 | ||
|  | 4f47e268cc | ||
|  | 0035b31cdb | ||
|  | f2565aee03 | ||
|  | 5bd85668dd | ||
|  | 20f990b6ce | ||
|  | 6821379586 | ||
|  | 73b040eb49 | ||
|  | 49aa4b2e1e | ||
|  | 972241c74c | ||
|  | 680750e3c2 | ||
|  | 5e7d4d9d15 | ||
|  | 1e57e60613 | ||
|  | 3ac7ce605a | ||
|  | b720dea9f0 | ||
|  | c80722aefe | ||
|  | a84fa69f28 | ||
|  | e33781e59f | ||
|  | 8824bc7ece | ||
|  | c2e3b0e448 | ||
|  | f61a38e85a | ||
|  | d23e948216 | ||
|  | 58bdaa31f0 | ||
|  | b6491d88a6 | ||
|  | f6061ba62e | ||
|  | 427899ddce | ||
|  | c4ab7d2dbd | ||
|  | 0fd2ba033f | ||
|  | ed38939a93 | ||
|  | c7ee26ce5a | ||
|  | 909b8cb303 | ||
|  | b0277370cf | ||
|  | 2ec8656bea | ||
|  | b2ef256910 | ||
|  | 63d6ce95db | ||
|  | a9532b189c | ||
|  | 844545411f | ||
|  | 4e23a2b9b8 | ||
|  | 5deba027eb | ||
|  | fc8b7efc6f | ||
|  | a1c2d9c0f3 | ||
|  | 4ca49a0501 | ||
|  | 493c53d090 | ||
|  | b27e956d35 | ||
|  | 35ebed75c6 | ||
|  | 7bfdb5f77f | ||
|  | 8d8c02317f | ||
|  | a34482feab | ||
|  | cbdc8fd4a6 | ||
|  | 8d3afaa53c | ||
|  | 7ced9ef3df | ||
|  | e8a9ae7e80 | ||
|  | 73a88ab3d3 | ||
|  | aaed82738a | ||
|  | de7f7b96db | ||
|  | 1a669b3e68 | ||
|  | 333af9b13a | ||
|  | a5bca5e240 | ||
|  | c885633e02 | ||
|  | ca7e20b7ca | ||
|  | 545e11a3d7 | ||
|  | 44f5287664 | ||
|  | cf510897f1 | ||
|  | 1d171345f8 | ||
|  | 4fa7e1cd49 | ||
|  | acd008298e | ||
|  | 83a8021515 | ||
|  | cf88dfb1db | ||
|  | 8937c4b481 | ||
|  | cc6af10a4d | ||
|  | 6d94578955 | ||
|  | 08442ab71e | ||
|  | 10d91d213f | ||
|  | b7a3b06994 | ||
|  | 5f12c37f23 | ||
|  | 585edebccd | ||
|  | 9921c62234 | ||
|  | 1ac76d2e16 | ||
|  | 6e983bf400 | ||
|  | 6a8fd4fa6e | ||
|  | 3698eaa2d2 | ||
|  | 8d97ca433c | ||
|  | 23cc65e537 | ||
|  | 2f5a3c2bbe | ||
|  | f6485616cd | ||
|  | 6544fb43d9 | ||
|  | a954b32dcc | ||
|  | 426dc7836c | ||
|  | ff941ffc16 | ||
|  | a063c201df | ||
|  | e2be3fa0aa | ||
|  | 609da6fb50 | ||
|  | fc9f3ccec3 | ||
|  | f7baa67a0a | ||
|  | e8d78c2cdb | ||
|  | 9d33366092 | ||
|  | f5d61515c2 | ||
|  | 711a04a972 | ||
|  | e5b470a3f1 | ||
|  | 31820e1e22 | ||
|  | 4849e8cd6d | ||
|  | 77e3b460aa | ||
|  | b5321001f8 | ||
|  | 38eba9f5ea | ||
|  | ea6f399454 | ||
|  | f8bf2d7b7d | ||
|  | c4856caebb | ||
|  | fc1030bb22 | ||
|  | 9eb6cad8dc | ||
|  | 0fa2a78dce | ||
|  | a56fa1558b | ||
|  | 261c73a997 | ||
|  | 929c1333ca | ||
|  | 286a79d94d | ||
|  | 8b951f99da | ||
|  | abb449bca0 | ||
|  | bd084028d1 | ||
|  | 138a27570b | ||
|  | c2ed40a74f | ||
|  | a7e7a00cab | ||
|  | 64a31ab3cd | ||
|  | 71958bc0f1 | ||
|  | 366ec35612 | ||
|  | 3738f6e8ae | ||
|  | 051a8e2af1 | ||
|  | 2f43f28d5e | ||
|  | b64769754b | ||
|  | a97daa18d1 | ||
|  | b6556dce8b | ||
|  | aa8d8bc8b5 | ||
|  | 0800dcfdc4 | ||
|  | 12b0101e94 | ||
|  | 021b391a02 | ||
|  | d11e2b6057 | ||
|  | 264d90e7e5 | ||
|  | f9f3da9e78 | ||
|  | 6435b49153 | ||
|  | f9aa2941cf | ||
|  | 5a933d4bee | ||
|  | 5536aea0df | ||
|  | 976666d216 | ||
|  | 9a5bcd4392 | ||
|  | 812060a118 | ||
|  | 089b5052e6 | ||
|  | 874e5d72f4 | ||
|  | 6b11de1329 | ||
|  | 2245a7ad8d | ||
|  | ee5ec1b870 | ||
|  | 74ccfe851b | ||
|  | e1c24bd5a2 | ||
|  | 1349b79728 | ||
|  | d294d7604c | ||
|  | 01df2cf464 | ||
|  | 45b7322488 | ||
|  | b3055e992f | ||
|  | 3da548565c | ||
|  | a975e85548 | ||
|  | c4b5ade752 | ||
|  | a4b61b0794 | ||
|  | f6011184b8 | ||
|  | 74de118c6e | ||
|  | 9c25e77c17 | ||
|  | 440113e67e | ||
|  | a11b60c445 | ||
|  | a6052681ad | ||
|  | 482d50536a | ||
|  | 25c79a4fcd | ||
|  | 02946144ac | ||
|  | 71a360e9a3 | ||
|  | f7912d88b1 | ||
|  | 975101d7d2 | ||
|  | ef58c5ff55 | ||
|  | e10221804a | ||
|  | 284ed9ee0e | ||
|  | 5d7b961997 | ||
|  | c699a5c4b4 | ||
|  | 1f4ceb89cf | ||
|  | 0934ca0040 | ||
|  | 4738f892c2 | ||
|  | 33004fcf33 | ||
|  | 34d214c166 | ||
|  | a56cd92a1e | ||
|  | 7251348507 | ||
|  | 01cd5c84d6 | ||
|  | e210599fa6 | ||
|  | dbe7cee7e9 | ||
|  | 7370d88ceb | ||
|  | 34458e0c57 | ||
|  | 05c8c3abf2 | ||
|  | e9d464b4d3 | ||
|  | 6968c3ab9b | ||
|  | 131a8a9650 | ||
|  | 379ecbf9a9 | ||
|  | 7b9dfa9a28 | ||
|  | fbd0f5eed2 | ||
|  | 5970f904ae | ||
|  | 8cbcb2868d | ||
|  | 8ff2a4b026 | ||
|  | ae14d205a5 | ||
|  | ec5d560ec5 | ||
|  | fb543b53c0 | ||
|  | 39c16422e2 | ||
|  | 4d5b273ebe | ||
|  | ed6a860fad | ||
|  | 423e579292 | ||
|  | ee11aa9e75 | ||
|  | c46d20fa92 | ||
|  | dc8d17574c | ||
|  | 5c17cd04c8 | ||
|  | 67ada02076 | ||
|  | 32d94c2eaf | ||
|  | 687b39a12a | ||
|  | 705af407bf | ||
|  | 080052da2e | ||
|  | ef735fd92a | ||
|  | 17c16dcafc | ||
|  | a89b3018fb | ||
|  | 851e2ebd32 | ||
|  | 1225ce7fe8 | ||
|  | 7e77a31b96 | ||
|  | d146b9002f | ||
|  | 1f9d567b23 | ||
|  | ed1b3a023c | ||
|  | 1ca18f501a | ||
|  | 49588ccd98 | ||
|  | 098dedc092 | ||
|  | b06f6b9545 | ||
|  | ba3cb94999 | ||
|  | 74c67fbf4b | ||
|  | 32b46e4910 | ||
|  | ecf5539ed2 | ||
|  | ac9db4e4d5 | ||
|  | 0eb96094b0 | ||
|  | 30b3ac7dc5 | ||
|  | 0092790c7d | ||
|  | 28909d8a51 | ||
|  | b20cfbb7b6 | ||
|  | 97639bd0a8 | ||
|  | 161ec73c96 | ||
|  | 957d6bea15 | ||
|  | f8b6e5b414 | ||
|  | 1ab450870e | ||
|  | de45f4884c | ||
|  | 5da1f3e7c8 | ||
|  | 983014952b | ||
|  | 55298019a3 | ||
|  | a1ffc3f271 | ||
|  | 2fb60aa997 | ||
|  | f5ec76537a | ||
|  | 728491fd2b | ||
|  | d9d3f2b9e4 | ||
|  | 3fe4864f65 | ||
|  | 0b156f22a4 | ||
|  | 35b1d93813 | ||
|  | d770851ac0 | ||
|  | 989e7b1033 | ||
|  | c4e0eb7b49 | ||
|  | 71f5d0dac7 | ||
|  | 561b0c4381 | ||
|  | 995fbc7330 | ||
|  | 10ab8949c4 | ||
|  | c441202fea | ||
|  | ca261b0bee | ||
|  | 52f3709f67 | ||
|  | c2ca6187fe | ||
|  | 671a13d295 | ||
|  | 14c3e2eccf | ||
|  | 08e5b852c2 | ||
|  | 1c9606c824 | ||
|  | 3cd47b5c9b | ||
|  | aedc729087 | ||
|  | 5f7cfa3fa9 | ||
|  | 0083f30af5 | ||
|  | 4a06f05ef5 | ||
|  | 8f37cadce8 | ||
|  | a11603ca6c | ||
|  | 86274842e9 | ||
|  | cf9c955a44 | ||
|  | 55d828c35f | ||
|  | cdff28aca6 | ||
|  | b9da39274f | ||
|  | c379aa5782 | ||
|  | 9dcabac9dd | ||
|  | 794f3a2b9f | ||
|  | 2066121b7c | ||
|  | 0c4067f143 | ||
|  | 8aa69243b7 | ||
|  | 8697263bde | ||
|  | ea25c4f65c | ||
|  | 82ac3ebd7e | ||
|  | 13cb94909c | ||
|  | b57ca2a763 | ||
|  | 83c49e9745 | ||
|  | e15771d78d | ||
|  | 6edc4920ba | ||
|  | 302bb1bd93 | ||
|  | 529b1bceee | ||
|  | 42cd47d32e | ||
|  | 711d884c2e | ||
|  | 183d1c4674 | ||
|  | faed63a0bb | ||
|  | 53bff262f8 | ||
|  | 3251a708e4 | ||
|  | b5dbdbf7b2 | ||
|  | a9649e92c9 | ||
|  | b561f1fa8b | ||
|  | cecd7491b5 | ||
|  | 55a66322b5 | ||
|  | 155c31a2d7 | ||
|  | a89ce91089 | ||
|  | b897fe6700 | ||
|  | 548a351b06 | ||
|  | 4b1da57ca1 | ||
|  | 529aec7f25 | ||
|  | 1661e545cb | ||
|  | ec71d08878 | ||
|  | ac258b7dd7 | ||
|  | 0f57876233 | ||
|  | 1d25a3693d | ||
|  | 45fa428bf1 | ||
|  | 177fa80f1a | ||
|  | 3261261bfe | ||
|  | d4de7934f8 | ||
|  | c3475af809 | ||
|  | b12f707812 | ||
|  | 22c0c34d60 | ||
|  | a60b66f230 | ||
|  | 83f6e93628 | ||
|  | 222b5f0229 | ||
|  | 30aa383e26 | ||
|  | 676b401294 | ||
|  | ebf57159de | ||
|  | 199d2aafec | ||
|  | 81952f56fd | ||
|  | c5bac82b43 | ||
|  | 081b86109c | ||
|  | 8ac2028a75 | ||
|  | 264fed1c9f | ||
|  | dd59f7b2c7 | ||
|  | 9245a760db | ||
|  | b61b32bbc3 | ||
|  | 09b3914f5d | ||
|  | fe644e4c9e | ||
|  | 7b09bf2156 | ||
|  | 987d0aae66 | ||
|  | 9cbcbc1c22 | ||
|  | cfc4e2bc60 | ||
|  | a03405fa81 | ||
|  | d5c9ccbe6e | ||
|  | e52772d65f | ||
|  | 1e3259e728 | ||
|  | e905a20a60 | ||
|  | 88e2be7a33 | ||
|  | 8939131600 | ||
|  | ba37ebff8b | ||
|  | 28f4cb7e07 | ||
|  | db1e7102cd | ||
|  | 07eb7a5830 | ||
|  | b7c6c685fa | ||
|  | 212134df70 | ||
|  | 6eeb5528f5 | ||
|  | 54fad845c9 | ||
|  | d6c0de6fc7 | ||
|  | 649c8649f7 | ||
|  | da2f53d1b1 | ||
|  | 405139e3b8 | ||
|  | 4f8d347171 | ||
|  | bf0db4876c | ||
|  | 47a14884d6 | ||
|  | 3a7bbc8b08 | ||
|  | 1b1d65372c | ||
|  | fd2faaa16e | ||
|  | 0609cdb9ea | ||
|  | d3bb140f89 | ||
|  | b31dc66628 | ||
|  | 09476171a6 | ||
|  | 33dee813b5 | ||
|  | bb4e73c40b | ||
|  | b1f23ffa94 | ||
|  | b0e8cec1e7 | ||
|  | 5077ae19bc | ||
|  | 0d8447bf59 | ||
|  | c6cf08a274 | ||
|  | dc49ae519e | ||
|  | 904539476a | ||
|  | 3fbf02dc82 | ||
|  | c9392a840d | ||
|  | d164e8ab72 | ||
|  | 6dc62c9fb6 | ||
|  | 87a9684d66 | ||
|  | 94525e2f44 | ||
|  | b408b1b3b9 | ||
|  | 27c2f09e32 | ||
|  | 19bc4d3349 | ||
|  | f2b6c424d6 | ||
|  | a49d4453e9 | ||
|  | 65e50087b9 | ||
|  | 2d90f759d9 | ||
|  | 4230ac7674 | ||
|  | d96e9182e9 | ||
|  | 68c87b9616 | ||
|  | 7f8e9a0b6d | ||
|  | 81a229f2a5 | ||
|  | 8be7ae2733 | ||
|  | 846bca4cb1 | ||
|  | f36f353789 | ||
|  | 939a2731ed | ||
|  | 835dab97ff | ||
|  | fa904b53be | ||
|  | 0ec52dddce | ||
|  | c289355a3a | ||
|  | 02a13a5a18 | ||
|  | 6cf2a0281b | ||
|  | 120d35f9af | ||
|  | 2b15d5e7b3 | ||
|  | fc167bd3f0 | ||
|  | 91b04abf05 | ||
|  | 77faac8740 | ||
|  | 43b3d54855 | ||
|  | 69e9b85700 | ||
|  | 0b6d132759 | ||
|  | 7c233c6c0c | ||
|  | c35b290fa4 | ||
|  | 3d95cfb367 | ||
|  | b90fc3a56e | ||
|  | 1ef3fdccf5 | ||
|  | 02b7f77bd8 | ||
|  | 0ac7ead922 | ||
|  | da9d0e03ce | ||
|  | 120f65f672 | ||
|  | 200a14caa4 | ||
|  | 35bf6da8e2 | ||
|  | f08f70276c | ||
|  | 1ae50fd95b | ||
|  | 40512beb47 | ||
|  | 0d7f9b2c94 | ||
|  | 52f42140a7 | ||
|  | 3f6c50297f | ||
|  | f72d80afc5 | ||
|  | 7c5cb13b22 | ||
|  | d728750eb2 | ||
|  | 02a70e5667 | ||
|  | 44e51ea5fa | ||
|  | 87e201460a | ||
|  | 039bd945e2 | ||
|  | e9e52d2b4b | ||
|  | 2bf92e7399 | ||
|  | 5b0df241f0 | ||
|  | 76f5b05eff | ||
|  | 40fb6c998f | ||
|  | 33f50a342d | ||
|  | 81523ab68a | ||
|  | 2bf8cc62cf | ||
|  | 1ae8247af3 | ||
|  | 5ef32227ec | ||
|  | 6456e773bd | ||
|  | 234fe53ca3 | ||
|  | 7c93e7a7b3 | ||
|  | 8afc6c7f4b | ||
|  | 4609d0fa3a | ||
|  | d452c035c6 | ||
|  | 45113c8f5a | ||
|  | 0acdd3c62b | ||
|  | 96d7d0a33e | ||
|  | b6b280267b | ||
|  | 6e6d253b1a | ||
|  | d92c105db2 | ||
|  | 906db728d6 | ||
|  | c4b7411565 | ||
|  | de06396046 | ||
|  | ee6bfeb8e3 | ||
|  | 058347321f | ||
|  | feefe49324 | ||
|  | 187381a9a2 | ||
|  | 993dfa4368 | ||
|  | 7e35a16440 | ||
|  | e4eeb15926 | ||
|  | 634e0db26d | ||
|  | 56855c23e1 | ||
|  | 0b00f742e3 | ||
|  | b7ab3f673c | ||
|  | be04ea1e35 | ||
|  | 1f8e695802 | ||
|  | 2d82b2c64f | ||
|  | d076caf473 | ||
|  | c7abdefa31 | ||
|  | ba772c0bca | ||
|  | 5bad234119 | ||
|  | c7e7baaf23 | ||
|  | 36658a671b | ||
|  | 045f2e10ba | ||
|  | fb5a7db66d | ||
|  | ba7d33982e | ||
|  | c62279a755 | ||
|  | 17fa1a7ffb | ||
|  | e89ceac351 | ||
|  | 0b8c30c109 | ||
|  | 9ab0f463cc | ||
|  | 6433dda7b8 | ||
|  | fa7a2f4be4 | ||
|  | ba90e16505 | ||
|  | 008f710203 | ||
|  | df2740f126 | ||
|  | 2db89d143e | ||
|  | 0525d49da3 | ||
|  | e2b0745882 | ||
|  | 92e804fc50 | ||
|  | 67abf45576 | ||
|  | d2c9c814e7 | ||
|  | 22f8881a64 | ||
|  | 4ab20322fe | ||
|  | 5370eeecea | ||
|  | ba71cb5dd7 | ||
|  | 9aad6c2c52 | ||
|  | 4d9627f20c | ||
|  | c142492e91 | ||
|  | 6bf8d9e207 | ||
|  | 4f9a6168c1 | ||
|  | 38397f99aa | ||
|  | f8686d0e75 | ||
|  | 549e3c8f9d | ||
|  | bb56225b95 | ||
|  | f00be261ba | ||
|  | 9cd94f26d0 | ||
|  | 4d8f5c80a7 | ||
|  | 24a23acc3d | ||
|  | ca8703cfd8 | ||
|  | 6dcbb5b2f8 | ||
|  | a84fdddb2a | ||
|  | 38bb2f8ceb | ||
|  | 23f5ef4345 | ||
|  | ef8a2a9054 | ||
|  | 96103d0e36 | ||
|  | ff5f6748df | ||
|  | 1c1fd6c366 | ||
|  | 32d37d00cb | ||
|  | 82f6cda966 | ||
|  | f1ff8ff0d0 | ||
|  | 756c72902f | ||
|  | 73f8f0bbd0 | ||
|  | 18ed528f5d | ||
|  | 8fd2f136bc | ||
|  | 0524b1bf67 | ||
|  | 15716f65ce | ||
|  | d46bdba332 | ||
|  | 760728110a | ||
|  | 12d0a194ca | ||
|  | 4104543508 | ||
|  | 5c211db015 | ||
|  | 2dc6180f8d | ||
|  | e222a34b69 | ||
|  | ef17d95063 | ||
|  | 853502e5d7 | ||
|  | c18e297e77 | ||
|  | c5a49599ba | ||
|  | df9da9edf5 | ||
|  | e2200fd050 | ||
|  | c6207f5d9c | ||
|  | 4302b7ff6b | ||
|  | 50a7923438 | ||
|  | ab416445c8 | ||
|  | a54698d43c | ||
|  | c5a77cc1c0 | ||
|  | a9ffa811fc | ||
|  | 080a2608e0 | ||
|  | 57f2e83d6a | ||
|  | 5b030139d3 | ||
|  | 0da1ff42d1 | ||
|  | 2c599b7baa | ||
|  | 5c8af8d21a | ||
|  | 026f3cfde2 | ||
|  | f6349180e8 | ||
|  | aa6421921c | ||
|  | 7d41d2dab2 | ||
|  | f0b4d18f93 | ||
|  | 6750f06e10 | ||
|  | b2bd38fa9e | ||
|  | 3482a01e22 | ||
|  | 6335467552 | ||
|  | 4a39e65b62 | ||
|  | c50a23e918 | ||
|  | 1e76b72b98 | ||
|  | b94cf39eef | ||
|  | fef254ffff | ||
|  | e5495863a2 | ||
|  | 3b4df2abf0 | ||
|  | aef2aee6a4 | ||
|  | d0d9519149 | ||
|  | 685df1d2c5 | ||
|  | 08e6b6f2e7 | ||
|  | 66c887d0f3 | ||
|  | 22e9960697 | ||
|  | 64aa6e1f2d | ||
|  | 7a93ed9d04 | ||
|  | a905e922e9 | ||
|  | f9f08fc720 | ||
|  | 8d402d76d0 | ||
|  | 46fda6281c | ||
|  | a14dbe1ea6 | ||
|  | 18810a4c16 | ||
|  | 147bc80dba | ||
|  | c7a484195a | ||
|  | 4968eb6503 | ||
|  | a6f2d698a9 | ||
|  | ea5ed93ea5 | ||
|  | e1140134c6 | ||
|  | 5ed11e012e | ||
|  | 5380bd39ca | ||
|  | 2ee2685688 | ||
|  | 782002245b | ||
|  | 7fc0905843 | ||
|  | 72ecb99e54 | ||
|  | c863507d08 | ||
|  | cff86c9093 | ||
|  | 0479dfcc54 | ||
|  | 68dd67f21c | ||
|  | 540f6858b5 | ||
|  | b61e791a4f | ||
|  | d0986f9482 | ||
|  | 112cb0dc28 | ||
|  | 0d3d7fdcf2 | ||
|  | 5d6b89ef3b | ||
|  | ed0b26c09e | ||
|  | ae292bd920 | ||
|  | 6c85a90723 | ||
|  | 852592066c | ||
|  | 96e1bc9b44 | ||
|  | b41d81ed31 | ||
|  | e241ec2244 | ||
|  | 16e1f1a94c | ||
|  | 7a68c42b26 | ||
|  | 37ccc2e118 | ||
|  | 4192fe1ab2 | ||
|  | d5c743d7bb | ||
|  | 11814d63e8 | ||
|  | b753656d50 | ||
|  | f7e87611fc | ||
|  | 1fb0e1900e | ||
|  | 954a9731e0 | ||
|  | 65c3364ad8 | ||
|  | 3d72b7dccc | ||
|  | 13ee569f06 | ||
|  | d79ef23a75 | ||
|  | 5d0797d4ba | ||
|  | 47a8d7475f | ||
|  | 4939053121 | ||
|  | b525bf554e | ||
|  | f00285d2b2 | ||
|  | 040f8d6eda | ||
|  | 66d905325c | ||
|  | 8b0cd95e73 | ||
|  | d867cca6d9 | ||
|  | a28f736369 | ||
|  | 5c3a71cc59 | ||
|  | cef6dadb08 | ||
|  | 36be817a3e | ||
|  | 02f571f081 | ||
|  | 157159e487 | ||
|  | 02ada9f800 | ||
|  | 6fcf9a97bb | ||
|  | 17a5d8799f | ||
|  | 31f3fe7a22 | ||
|  | 89e46d3d83 | ||
|  | 885795e67d | ||
|  | 92bfb53dd4 | ||
|  | 4cecbeb115 | ||
|  | 5971480f55 | ||
|  | 05bebea511 | ||
|  | 76fa6c5cfb | ||
|  | 633b68b518 | ||
|  | 6913d8e995 | ||
|  | f3654e6f8d | ||
|  | d685dbcf22 | ||
|  | 6a57fa079e | ||
|  | 0a91d145ba | ||
|  | c2866e799d | ||
|  | d8cffcaae7 | ||
|  | 30abca7be2 | ||
|  | edce87f3fb | ||
|  | 66bac98fc2 | ||
|  | 59156de92b | ||
|  | e0d7d10600 | ||
|  | daaf862257 | ||
|  | 9de53d4b59 | ||
|  | f1571e2d46 | ||
|  | bd28d06298 | ||
|  | a24e4655eb | ||
|  | 20a6c8d8e5 | ||
|  | 98d264faf4 | ||
|  | 321902a9b5 | ||
|  | 8df5d06f9a | ||
|  | e69ea529cc | ||
|  | 15405b1119 | ||
|  | d2f97ce2da | ||
|  | 543ca631e9 | ||
|  | f184886db1 | ||
|  | 8432ab4324 | ||
|  | 6c05b37ca3 | ||
|  | 35f4beeb47 | ||
|  | cbad7caa68 | ||
|  | b0388a4012 | ||
|  | df3fab4d55 | ||
|  | da49f88a03 | ||
|  | e28feceb06 | ||
|  | 50496a164d | ||
|  | 6f1dce1572 | ||
|  | 6847776ae7 | ||
|  | 67bd53bdd8 | ||
|  | e735abfdfd | ||
|  | 1de93a2d6d | ||
|  | 36f9e7c742 | ||
|  | 9462763bbb | ||
|  | 4ae0880ea6 | ||
|  | 6ae2b6c835 | ||
|  | a0f180fd48 | ||
|  | bf1cf89914 | ||
|  | 297a047fb4 | ||
|  | 52ffc15ffc | ||
|  | e478c9c693 | ||
|  | d004f28074 | ||
|  | bc68ed8b1d | ||
|  | 04555ae650 | ||
|  | e8f62085be | ||
|  | f430bffe2a | ||
|  | 1f0520634f | ||
|  | 902d4c31fb | ||
|  | 17364ac09f | ||
|  | 0b889f8f81 | ||
|  | 40e349ff35 | ||
|  | c943b1b1df | ||
|  | 912bc1d4e1 | ||
|  | cacb1533a3 | ||
|  | f0feaca9d7 | ||
|  | b6656f171b | ||
|  | 6206ab3931 | ||
|  | c35fc58b1f | ||
|  | deed8abed7 | ||
|  | 7151ad23f0 | ||
|  | 0166d938af | ||
|  | 6194aeddb0 | ||
|  | 903dbf2c30 | ||
|  | 9380f9ff57 | ||
|  | 259ed95486 | ||
|  | 2ebc92681e | ||
|  | 195a1ffe13 | ||
|  | a8c2978185 | ||
|  | 140f97a457 | ||
|  | 7f94445a1e | ||
|  | 82a89aec65 | ||
|  | 7e95110232 | ||
|  | ec4aaaad89 | ||
|  | 1b790fde24 | ||
|  | aaccea731e | ||
|  | 29e31d7610 | ||
|  | aa51f4a98f | ||
|  | e6ccd12f00 | ||
|  | b134315df1 | ||
|  | 7f34dffa13 | ||
|  | fa239e78c9 | ||
|  | 707a6c4d6a | ||
|  | e5da303b43 | ||
|  | 84ccd66331 | ||
|  | ad8cc2baea | ||
|  | 7c4cf70309 | ||
|  | c3211e9b4f | ||
|  | 268d94c983 | ||
|  | 0bcacbba58 | ||
|  | 8cdc26add9 | ||
|  | e0b2238886 | ||
|  | 369a2e4029 | ||
|  | c4089e3b51 | ||
|  | 9e2e9bc5b8 | ||
|  | a9e44426ed | 
							
								
								
									
										27
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,27 +0,0 @@ | ||||
| *.5 | ||||
| *.8 | ||||
| *.a | ||||
| *.d | ||||
| *.o | ||||
| *.pc | ||||
| *.pot | ||||
| *.so | ||||
| *.so.* | ||||
| *.swp | ||||
| *~ | ||||
|  | ||||
| .export.sym | ||||
| .exported_symbols_generated | ||||
| .gdb_history | ||||
|  | ||||
| Makefile | ||||
| make.tmpl | ||||
|  | ||||
| configure.h | ||||
| version.h | ||||
|  | ||||
| /autom4te.cache/ | ||||
| /config.log | ||||
| /config.status | ||||
| /cscope.out | ||||
| /tmp/ | ||||
							
								
								
									
										203
									
								
								COPYING.LIB
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								COPYING.LIB
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | ||||
| 		  GNU LESSER GENERAL PUBLIC LICENSE | ||||
| 		       Version 2.1, February 1999 | ||||
|  | ||||
|  Copyright (C) 1991, 1999 Free Software Foundation, Inc. | ||||
|  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| 		  GNU LIBRARY GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1991 Free Software Foundation, Inc. | ||||
|  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
| [This is the first released version of the Lesser GPL.  It also counts | ||||
|  as the successor of the GNU Library Public License, version 2, hence | ||||
|  the version number 2.1.] | ||||
| [This is the first released version of the library GPL.  It is | ||||
|  numbered 2 because it goes with version 2 of the ordinary GPL.] | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
| @@ -17,109 +17,97 @@ freedom to share and change it.  By contrast, the GNU General Public | ||||
| Licenses are intended to guarantee your freedom to share and change | ||||
| free software--to make sure the software is free for all its users. | ||||
|  | ||||
|   This license, the Lesser General Public License, applies to some | ||||
| specially designated software packages--typically libraries--of the | ||||
| Free Software Foundation and other authors who decide to use it.  You | ||||
| can use it too, but we suggest you first think carefully about whether | ||||
| this license or the ordinary General Public License is the better | ||||
| strategy to use in any particular case, based on the explanations below. | ||||
|   This license, the Library General Public License, applies to some | ||||
| specially designated Free Software Foundation software, and to any | ||||
| other libraries whose authors decide to use it.  You can use it for | ||||
| your libraries, too. | ||||
|  | ||||
|   When we speak of free software, we are referring to freedom of use, | ||||
| not price.  Our General Public Licenses are designed to make sure that | ||||
| you have the freedom to distribute copies of free software (and charge | ||||
| for this service if you wish); that you receive source code or can get | ||||
| it if you want it; that you can change the software and use pieces of | ||||
| it in new free programs; and that you are informed that you can do | ||||
| these things. | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| this service if you wish), that you receive source code or can get it | ||||
| if you want it, that you can change the software or use pieces of it | ||||
| in new free programs; and that you know you can do these things. | ||||
|  | ||||
|   To protect your rights, we need to make restrictions that forbid | ||||
| distributors to deny you these rights or to ask you to surrender these | ||||
| rights.  These restrictions translate to certain responsibilities for | ||||
| you if you distribute copies of the library or if you modify it. | ||||
| anyone to deny you these rights or to ask you to surrender the rights. | ||||
| These restrictions translate to certain responsibilities for you if | ||||
| you distribute copies of the library, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of the library, whether gratis | ||||
| or for a fee, you must give the recipients all the rights that we gave | ||||
| you.  You must make sure that they, too, receive or can get the source | ||||
| code.  If you link other code with the library, you must provide | ||||
| complete object files to the recipients, so that they can relink them | ||||
| with the library after making changes to the library and recompiling | ||||
| code.  If you link a program with the library, you must provide | ||||
| complete object files to the recipients so that they can relink them | ||||
| with the library, after making changes to the library and recompiling | ||||
| it.  And you must show them these terms so they know their rights. | ||||
|  | ||||
|   We protect your rights with a two-step method: (1) we copyright the | ||||
| library, and (2) we offer you this license, which gives you legal | ||||
|   Our method of protecting your rights has two steps: (1) copyright | ||||
| the library, and (2) offer you this license which gives you legal | ||||
| permission to copy, distribute and/or modify the library. | ||||
|  | ||||
|   To protect each distributor, we want to make it very clear that | ||||
| there is no warranty for the free library.  Also, if the library is | ||||
| modified by someone else and passed on, the recipients should know | ||||
| that what they have is not the original version, so that the original | ||||
| author's reputation will not be affected by problems that might be | ||||
| introduced by others. | ||||
|   Also, for each distributor's protection, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| library.  If the library is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original | ||||
| version, so that any problems introduced by others will not reflect on | ||||
| the original authors' reputations. | ||||
|  | ||||
|   Finally, software patents pose a constant threat to the existence of | ||||
| any free program.  We wish to make sure that a company cannot | ||||
| effectively restrict the users of a free program by obtaining a | ||||
| restrictive license from a patent holder.  Therefore, we insist that | ||||
| any patent license obtained for a version of the library must be | ||||
| consistent with the full freedom of use specified in this license. | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that companies distributing free | ||||
| software will individually obtain patent licenses, thus in effect | ||||
| transforming the program into proprietary software.  To prevent this, | ||||
| we have made it clear that any patent must be licensed for everyone's | ||||
| free use or not licensed at all. | ||||
|  | ||||
|   Most GNU software, including some libraries, is covered by the | ||||
| ordinary GNU General Public License.  This license, the GNU Lesser | ||||
| General Public License, applies to certain designated libraries, and | ||||
| is quite different from the ordinary General Public License.  We use | ||||
| this license for certain libraries in order to permit linking those | ||||
| libraries into non-free programs. | ||||
|   Most GNU software, including some libraries, is covered by the ordinary | ||||
| GNU General Public License, which was designed for utility programs.  This | ||||
| license, the GNU Library General Public License, applies to certain | ||||
| designated libraries.  This license is quite different from the ordinary | ||||
| one; be sure to read it in full, and don't assume that anything in it is | ||||
| the same as in the ordinary license. | ||||
|  | ||||
|   When a program is linked with a library, whether statically or using | ||||
| a shared library, the combination of the two is legally speaking a | ||||
| combined work, a derivative of the original library.  The ordinary | ||||
| General Public License therefore permits such linking only if the | ||||
| entire combination fits its criteria of freedom.  The Lesser General | ||||
| Public License permits more lax criteria for linking other code with | ||||
| the library. | ||||
|   The reason we have a separate public license for some libraries is that | ||||
| they blur the distinction we usually make between modifying or adding to a | ||||
| program and simply using it.  Linking a program with a library, without | ||||
| changing the library, is in some sense simply using the library, and is | ||||
| analogous to running a utility program or application program.  However, in | ||||
| a textual and legal sense, the linked executable is a combined work, a | ||||
| derivative of the original library, and the ordinary General Public License | ||||
| treats it as such. | ||||
|  | ||||
|   We call this license the "Lesser" General Public License because it | ||||
| does Less to protect the user's freedom than the ordinary General | ||||
| Public License.  It also provides other free software developers Less | ||||
| of an advantage over competing non-free programs.  These disadvantages | ||||
| are the reason we use the ordinary General Public License for many | ||||
| libraries.  However, the Lesser license provides advantages in certain | ||||
| special circumstances. | ||||
|   Because of this blurred distinction, using the ordinary General | ||||
| Public License for libraries did not effectively promote software | ||||
| sharing, because most developers did not use the libraries.  We | ||||
| concluded that weaker conditions might promote sharing better. | ||||
|  | ||||
|   For example, on rare occasions, there may be a special need to | ||||
| encourage the widest possible use of a certain library, so that it becomes | ||||
| a de-facto standard.  To achieve this, non-free programs must be | ||||
| allowed to use the library.  A more frequent case is that a free | ||||
| library does the same job as widely used non-free libraries.  In this | ||||
| case, there is little to gain by limiting the free library to free | ||||
| software only, so we use the Lesser General Public License. | ||||
|  | ||||
|   In other cases, permission to use a particular library in non-free | ||||
| programs enables a greater number of people to use a large body of | ||||
| free software.  For example, permission to use the GNU C Library in | ||||
| non-free programs enables many more people to use the whole GNU | ||||
| operating system, as well as its variant, the GNU/Linux operating | ||||
| system. | ||||
|  | ||||
|   Although the Lesser General Public License is Less protective of the | ||||
| users' freedom, it does ensure that the user of a program that is | ||||
| linked with the Library has the freedom and the wherewithal to run | ||||
| that program using a modified version of the Library. | ||||
|   However, unrestricted linking of non-free programs would deprive the | ||||
| users of those programs of all benefit from the free status of the | ||||
| libraries themselves.  This Library General Public License is intended to | ||||
| permit developers of non-free programs to use free libraries, while | ||||
| preserving your freedom as a user of such programs to change the free | ||||
| libraries that are incorporated in them.  (We have not seen how to achieve | ||||
| this as regards changes in header files, but we have achieved it as regards | ||||
| changes in the actual functions of the Library.)  The hope is that this | ||||
| will lead to faster development of free libraries. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow.  Pay close attention to the difference between a | ||||
| "work based on the library" and a "work that uses the library".  The | ||||
| former contains code derived from the library, whereas the latter must | ||||
| be combined with the library in order to run. | ||||
| former contains code derived from the library, while the latter only | ||||
| works together with the library. | ||||
|  | ||||
|   Note that it is possible for a library to be covered by the ordinary | ||||
| General Public License rather than by this special one. | ||||
|  | ||||
| 		  GNU LESSER GENERAL PUBLIC LICENSE | ||||
| 		  GNU LIBRARY GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License Agreement applies to any software library or other | ||||
| program which contains a notice placed by the copyright holder or | ||||
| other authorized party saying it may be distributed under the terms of | ||||
| this Lesser General Public License (also called "this License"). | ||||
| Each licensee is addressed as "you". | ||||
|   0. This License Agreement applies to any software library which | ||||
| contains a notice placed by the copyright holder or other authorized | ||||
| party saying it may be distributed under the terms of this Library | ||||
| General Public License (also called "this License").  Each licensee is | ||||
| addressed as "you". | ||||
|  | ||||
|   A "library" means a collection of software functions and/or data | ||||
| prepared so as to be conveniently linked with application programs | ||||
| @@ -268,7 +256,7 @@ distribute the object code for the work under the terms of Section 6. | ||||
| Any executables containing that work also fall under Section 6, | ||||
| whether or not they are linked directly with the Library itself. | ||||
|  | ||||
|   6. As an exception to the Sections above, you may also combine or | ||||
|   6. As an exception to the Sections above, you may also compile or | ||||
| link a "work that uses the Library" with the Library to produce a | ||||
| work containing portions of the Library, and distribute that work | ||||
| under terms of your choice, provided that the terms permit | ||||
| @@ -295,31 +283,23 @@ of these things: | ||||
|     Library will not necessarily be able to recompile the application | ||||
|     to use the modified definitions.) | ||||
|  | ||||
|     b) Use a suitable shared library mechanism for linking with the | ||||
|     Library.  A suitable mechanism is one that (1) uses at run time a | ||||
|     copy of the library already present on the user's computer system, | ||||
|     rather than copying library functions into the executable, and (2) | ||||
|     will operate properly with a modified version of the library, if | ||||
|     the user installs one, as long as the modified version is | ||||
|     interface-compatible with the version that the work was made with. | ||||
|  | ||||
|     c) Accompany the work with a written offer, valid for at | ||||
|     b) Accompany the work with a written offer, valid for at | ||||
|     least three years, to give the same user the materials | ||||
|     specified in Subsection 6a, above, for a charge no more | ||||
|     than the cost of performing this distribution. | ||||
|  | ||||
|     d) If distribution of the work is made by offering access to copy | ||||
|     c) If distribution of the work is made by offering access to copy | ||||
|     from a designated place, offer equivalent access to copy the above | ||||
|     specified materials from the same place. | ||||
|  | ||||
|     e) Verify that the user has already received a copy of these | ||||
|     d) Verify that the user has already received a copy of these | ||||
|     materials or that you have already sent this user a copy. | ||||
|  | ||||
|   For an executable, the required form of the "work that uses the | ||||
| Library" must include any data and utility programs needed for | ||||
| reproducing the executable from it.  However, as a special exception, | ||||
| the materials to be distributed need not include anything that is | ||||
| normally distributed (in either source or binary form) with the major | ||||
| the source code distributed need not include anything that is normally | ||||
| distributed (in either source or binary form) with the major | ||||
| components (compiler, kernel, and so on) of the operating system on | ||||
| which the executable runs, unless that component itself accompanies | ||||
| the executable. | ||||
| @@ -368,7 +348,7 @@ Library), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute, link with or modify the Library | ||||
| subject to these terms and conditions.  You may not impose any further | ||||
| restrictions on the recipients' exercise of the rights granted herein. | ||||
| You are not responsible for enforcing compliance by third parties with | ||||
| You are not responsible for enforcing compliance by third parties to | ||||
| this License. | ||||
|  | ||||
|   11. If, as a consequence of a court judgment or allegation of patent | ||||
| @@ -411,7 +391,7 @@ excluded.  In such case, this License incorporates the limitation as if | ||||
| written in the body of this License. | ||||
|  | ||||
|   13. The Free Software Foundation may publish revised and/or new | ||||
| versions of the Lesser General Public License from time to time. | ||||
| versions of the Library General Public License from time to time. | ||||
| Such new versions will be similar in spirit to the present version, | ||||
| but may differ in detail to address new problems or concerns. | ||||
|  | ||||
| @@ -457,7 +437,7 @@ DAMAGES. | ||||
|  | ||||
| 		     END OF TERMS AND CONDITIONS | ||||
|  | ||||
|            How to Apply These Terms to Your New Libraries | ||||
|      Appendix: How to Apply These Terms to Your New Libraries | ||||
|  | ||||
|   If you develop a new library, and you want it to be of the greatest | ||||
| possible use to the public, we recommend making it free software that | ||||
| @@ -474,18 +454,19 @@ convey the exclusion of warranty; and each file should have at least the | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     This library is free software; you can redistribute it and/or | ||||
|     modify it under the terms of the GNU Lesser General Public | ||||
|     modify it under the terms of the GNU Library General Public | ||||
|     License as published by the Free Software Foundation; either | ||||
|     version 2.1 of the License, or (at your option) any later version. | ||||
|     version 2 of the License, or (at your option) any later version. | ||||
|  | ||||
|     This library 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 | ||||
|     Lesser General Public License for more details. | ||||
|     Library General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU Lesser General Public | ||||
|     License along with this library; if not, write to the Free Software | ||||
|     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | ||||
|     You should have received a copy of the GNU Library General Public | ||||
|     License along with this library; if not, write to the Free | ||||
|     Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | ||||
|     MA 02111-1307, USA | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| @@ -500,5 +481,3 @@ necessary.  Here is a sample; alter the names: | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| That's all there is to it! | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										34
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								INSTALL
									
									
									
									
									
								
							| @@ -1,30 +1,44 @@ | ||||
| Installation | ||||
| ============ | ||||
| LVM2 installation | ||||
| ================= | ||||
|  | ||||
| 1) Generate custom makefiles. | ||||
| 1) Install device-mapper | ||||
|  | ||||
|    Ensure the device-mapper has been installed on the machine. | ||||
|  | ||||
|    The device-mapper should be in the kernel (look for 'device-mapper' | ||||
|    messages in the kernel logs) and /usr/include/libdevmapper.h  | ||||
|    and libdevmapper.so should be present. | ||||
|  | ||||
|    The device-mapper is available from: | ||||
|      ftp://ftp.sistina.com/pub/LVM2/device-mapper/ | ||||
|  | ||||
|  | ||||
| 2) Generate custom makefiles. | ||||
|  | ||||
|    Run the 'configure' script from the top directory. | ||||
|  | ||||
|    If you wish to use the built-in LVM2 shell and have GNU readline  | ||||
|    installed (http://www.gnu.org/directory/readline.html) use: | ||||
|      ./configure --enable-readline | ||||
|  | ||||
|    If you don't want to include the LVM1 backwards-compatibility code use: | ||||
|      ./configure --with-lvm1=none  | ||||
|  | ||||
|    To separate the LVM1 support into a shared library loaded by lvm.conf use: | ||||
|      ./configure --with-lvm1=shared | ||||
|  | ||||
|    Use ./configure --help to see other options. | ||||
|  | ||||
| 2) Build and install. | ||||
| 3) Build and install LVM2. | ||||
|  | ||||
|    Run 'make' from the top directory to build everything you configured. | ||||
|    Run 'make install' to build and install everything you configured. | ||||
|    Run 'make install' from the top directory. | ||||
|  | ||||
|    If you only want the device-mapper libraries and tools use | ||||
|    'make device-mapper' or 'make install_device-mapper'. | ||||
|  | ||||
| 3) If using LVM2, create a configuration file. | ||||
| 4) Create a configuration file | ||||
|  | ||||
|    The tools will work fine without a configuration file being | ||||
|    present, but you ought to review the example file in doc/example.conf. | ||||
|    For example, specifying the devices that LVM2 is to use can | ||||
|    make the tools run more efficiently - and avoid scanning /dev/cdrom! | ||||
|  | ||||
| Please also refer to the WHATS_NEW file and the manual pages for the  | ||||
| individual commands. | ||||
|   | ||||
							
								
								
									
										168
									
								
								Makefile.in
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								Makefile.in
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # This file is part of the LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| @@ -14,173 +14,35 @@ | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
| VPATH = @srcdir@ | ||||
|  | ||||
| SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools | ||||
|  | ||||
| ifeq ("@UDEV_RULES@", "yes") | ||||
|   SUBDIRS += udev | ||||
| endif | ||||
| SUBDIRS = doc include man  | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
|   SUBDIRS += po | ||||
| endif | ||||
|  | ||||
| ifeq ("@APPLIB@", "yes") | ||||
|   SUBDIRS += liblvm | ||||
| endif | ||||
| SUBDIRS += lib tools | ||||
|  | ||||
| ifeq ("@PYTHON_BINDINGS@", "yes") | ||||
|   SUBDIRS += python | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),clean) | ||||
|   SUBDIRS += test | ||||
| endif | ||||
| # FIXME Should use intermediate Makefiles here! | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = conf include man test scripts \ | ||||
|     libdaemon lib tools daemons libdm \ | ||||
|     udev po liblvm python \ | ||||
|     unit-tests/datastruct unit-tests/mm unit-tests/regex | ||||
| tools.distclean: test.distclean | ||||
|   SUBDIRS += lib/format1 \ | ||||
| 	     lib/format_pool \ | ||||
| 	     lib/mirror \ | ||||
| 	     lib/snapshot \ | ||||
| 	     po \ | ||||
| 	     test/mm test/device test/format1 test/regex test/filters | ||||
| endif | ||||
| DISTCLEAN_DIRS += lcov_reports* | ||||
| DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl | ||||
|  | ||||
| include make.tmpl | ||||
|  | ||||
| libdm: include | ||||
| libdaemon: include | ||||
| lib: libdm libdaemon | ||||
| liblvm: lib | ||||
| daemons: lib libdaemon tools | ||||
| tools: lib libdaemon device-mapper | ||||
| po: tools daemons | ||||
| scripts: liblvm libdm | ||||
|  | ||||
| lib.device-mapper: include.device-mapper | ||||
| libdm.device-mapper: include.device-mapper | ||||
| liblvm.device-mapper: include.device-mapper | ||||
| daemons.device-mapper: libdm.device-mapper | ||||
| tools.device-mapper: libdm.device-mapper | ||||
| scripts.device-mapper: include.device-mapper | ||||
| device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper | ||||
| lib: include | ||||
| tools: lib | ||||
| po: lib tools | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
| lib.pofile: include.pofile | ||||
| tools.pofile: lib.pofile | ||||
| daemons.pofile: lib.pofile | ||||
| po.pofile: tools.pofile daemons.pofile | ||||
| po.pofile: lib.pofile tools.pofile | ||||
| pofile: po.pofile | ||||
| endif | ||||
|  | ||||
| ifeq ("@PYTHON_BINDINGS@", "yes") | ||||
| python: liblvm | ||||
| endif | ||||
|  | ||||
| ifneq ("$(CFLOW_CMD)", "") | ||||
| tools.cflow: libdm.cflow lib.cflow | ||||
| daemons.cflow: tools.cflow | ||||
| cflow: include.cflow | ||||
| endif | ||||
|  | ||||
| ifneq ("@CSCOPE_CMD@", "") | ||||
| cscope.out: | ||||
| 	@CSCOPE_CMD@ -b -R -s$(top_srcdir) | ||||
| all: cscope.out | ||||
| endif | ||||
| DISTCLEAN_TARGETS += cscope.out | ||||
|  | ||||
| check check_system check_cluster check_local check_lvmetad unit: all | ||||
| 	$(MAKE) -C test $(@) | ||||
|  | ||||
| install_system_dirs: | ||||
| 	$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_LOCK_DIR) | ||||
| 	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR) | ||||
| 	$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache | ||||
|  | ||||
| install_initscripts:  | ||||
| 	$(MAKE) -C scripts install_initscripts | ||||
|  | ||||
| install_systemd_generators: | ||||
| 	$(MAKE) -C scripts install_systemd_generators | ||||
| 	$(MAKE) -C man install_systemd_generators | ||||
|  | ||||
| install_systemd_units: | ||||
| 	$(MAKE) -C scripts install_systemd_units | ||||
|  | ||||
| ifeq ("@PYTHON_BINDINGS@", "yes") | ||||
| install_python_bindings: | ||||
| 	$(MAKE) -C liblvm/python install_python_bindings | ||||
| endif | ||||
|  | ||||
| install_tmpfiles_configuration: | ||||
| 	$(MAKE) -C scripts install_tmpfiles_configuration | ||||
|  | ||||
| LCOV_TRACES = libdm.info lib.info tools.info \ | ||||
| 	daemons/dmeventd.info daemons/clvmd.info | ||||
| CLEAN_TARGETS += $(LCOV_TRACES) | ||||
|  | ||||
| ifneq ("$(LCOV)", "") | ||||
| .PHONY: lcov-reset lcov lcov-dated $(LCOV_TRACES) | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),lcov-dated) | ||||
| LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S) | ||||
| lcov-dated: lcov | ||||
| else | ||||
| LCOV_REPORTS_DIR := lcov_reports | ||||
| endif | ||||
|  | ||||
| lcov-reset: | ||||
| 	$(LCOV) --zerocounters $(addprefix -d , $(basename $(LCOV_TRACES))) | ||||
|  | ||||
| # maybe use subdirs processing to create tracefiles... | ||||
| $(LCOV_TRACES): | ||||
| 	$(LCOV) -b $(basename $@) -d $(basename $@) \ | ||||
| 		--ignore-errors source -c -o - | $(SED) \ | ||||
| 		-e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \ | ||||
| 		-e "s/dmeventd_\(mirror\|snapshot\|thin\|raid\)\.c/plugins\/\1\/dmeventd_\1\.c/" \ | ||||
| 		>$@ | ||||
|  | ||||
| ifneq ("$(GENHTML)", "") | ||||
| lcov: $(LCOV_TRACES) | ||||
| 	$(RM) -r $(LCOV_REPORTS_DIR) | ||||
| 	$(MKDIR_P) $(LCOV_REPORTS_DIR) | ||||
| 	for i in $(LCOV_TRACES); do \ | ||||
| 		test -s $$i && lc="$$lc $$i"; \ | ||||
| 	done; \ | ||||
| 	test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \ | ||||
| 		-o $(LCOV_REPORTS_DIR) $$lc | ||||
| endif | ||||
|  | ||||
| endif | ||||
|  | ||||
| ifeq ("$(TESTING)", "yes") | ||||
| # testing and report generation | ||||
| RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test | ||||
|  | ||||
| .PHONY: unit-test ruby-test test-programs | ||||
|  | ||||
| # FIXME: put dependencies on libdm and liblvm | ||||
| # FIXME: Should be handled by Makefiles in subdirs, not here at top level. | ||||
| test-programs: | ||||
| 	cd unit-tests/regex && $(MAKE) | ||||
| 	cd unit-tests/datastruct && $(MAKE) | ||||
| 	cd unit-tests/mm && $(MAKE) | ||||
|  | ||||
| unit-test: test-programs | ||||
| 	$(RUBY) report-generators/unit_test.rb $(shell find . -name TESTS) | ||||
| 	$(RUBY) report-generators/title_page.rb | ||||
|  | ||||
| memcheck: test-programs | ||||
| 	$(RUBY) report-generators/memcheck.rb $(shell find . -name TESTS) | ||||
| 	$(RUBY) report-generators/title_page.rb | ||||
|  | ||||
| ruby-test: | ||||
| 	$(RUBY) report-generators/test/ts.rb | ||||
| endif | ||||
|   | ||||
							
								
								
									
										34
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								README
									
									
									
									
									
								
							| @@ -1,33 +1,23 @@ | ||||
| This tree contains the LVM2 and device-mapper tools and libraries. | ||||
| This directory contains LVM2, the new version of the userland LVM | ||||
| tools designed for the new device-mapper for the Linux kernel. | ||||
|  | ||||
| For more information about LVM2 read the changelog in the WHATS_NEW file. | ||||
| The device-mapper needs to be installed before compiling these LVM2 tools. | ||||
|  | ||||
| For more information about LVM2 read the WHATS_NEW file. | ||||
| Installation instructions are in INSTALL. | ||||
|  | ||||
| There is no warranty - see COPYING and COPYING.LIB. | ||||
|  | ||||
| Tarballs are available from: | ||||
|   ftp://sources.redhat.com/pub/lvm2/ | ||||
|   ftp://ftp.sistina.com/pub/LVM2/tools/ | ||||
|   ftp://ftp.sistina.com/pub/LVM2/device-mapper/ | ||||
|  | ||||
| The source code is stored in git: | ||||
|   http://git.fedorahosted.org/git/lvm2.git | ||||
|   git clone git://git.fedorahosted.org/git/lvm2.git | ||||
| To access the CVS tree use: | ||||
|   cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login | ||||
|   CVS password: cvs | ||||
|   cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 co LVM2 | ||||
|  | ||||
| Mailing list for general discussion related to LVM2: | ||||
| Mailing list for discussion/bug reports etc. | ||||
|   linux-lvm@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
|  | ||||
| Mailing lists for LVM2 development, patches and commits: | ||||
|   lvm-devel@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
|  | ||||
|   lvm2-commits@lists.fedorahosted.org (Read-only archive of commits) | ||||
|   Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits | ||||
|  | ||||
| Mailing list for device-mapper development, including kernel patches | ||||
| and multipath-tools: | ||||
|   dm-devel@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel | ||||
|  | ||||
| The source code repository used until 7th June 2012 is accessible here: | ||||
|   http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2. | ||||
|  | ||||
|   | ||||
| @@ -1 +0,0 @@ | ||||
| 1.02.91-git (2014-09-01) | ||||
							
								
								
									
										912
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										912
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							| @@ -1,914 +1,5 @@ | ||||
| Version 1.02.91 -  | ||||
| ==================================== | ||||
|   Fix dm_is_dm_major to not issue error about missing /proc lines for dm module. | ||||
|  | ||||
| Version 1.02.90 - 1st September 2014 | ||||
| ==================================== | ||||
|   Restore proper buffer size for parsing mountinfo line (1.02.89) | ||||
|  | ||||
| Version 1.02.89 - 26th August 2014 | ||||
| ================================== | ||||
|   Improve libdevmapper-event select() error handling. | ||||
|   Add extra check for matching transation_id after message submitting. | ||||
|   Add dm_report_field_string_list_unsorted for str. list report without sorting. | ||||
|   Support --deferred with dmsetup remove to defer removal of open devices. | ||||
|   Update dm-ioctl.h to include DM_DEFERRED_REMOVE flag. | ||||
|   Add support for selection to match string list subset, recognize { } operator. | ||||
|   Fix string list selection with '[value]' to not match list that's superset. | ||||
|   Fix string list selection to match whole words only, not prefixes. | ||||
|  | ||||
| Version 1.02.88 - 5th August 2014 | ||||
| ================================= | ||||
|   Add dm_tree_set_optional_uuid_suffixes to handle upgrades. | ||||
|  | ||||
| Version 1.02.87 - 23rd July 2014 | ||||
| ================================ | ||||
|   Fix dm_report_field_string_list to handle delimiter with multiple chars. | ||||
|   Add dm_report_field_reserved_value for per-field reserved value definition. | ||||
|  | ||||
| Version 1.02.86 - 23rd June 2014 | ||||
| ================================ | ||||
|   Make "help" and "?" reporting fields implicit. | ||||
|   Recognize implicit "selected" field if using dm_report_init_with_selection. | ||||
|   Add support for implicit reporting fields which are predefined in libdm. | ||||
|   Add DM_REPORT_FIELD_TYPE_PERCENT: separate number and percent fields. | ||||
|   Add dm_percent_range_t,dm_percent_to_float,dm_make_percent to libdm for reuse. | ||||
|   Add dm_report_reserved_value to libdevmapper for reserved value definition. | ||||
|   Also display field types when listing all fields in selection help. | ||||
|   Recognize "help" keyword in selection string to show brief help for selection. | ||||
|   Always order items reported as string list field lexicographically. | ||||
|   Add dm_report_field_string_list to libdevmapper for direct string list report. | ||||
|   Add DM_REPORT_FIELD_TYPE_STRING_LIST: separate string and string list fields. | ||||
|   Add dm_str_list to libdevmapper for string list type definition and its reuse. | ||||
|   Add dmsetup -S/--select to define selection criteria for dmsetup reports. | ||||
|   Add dm_report_init_with_selection to intialize report with selection criteria. | ||||
|   Add DM_REPORT_FIELD_TYPE_SIZE: separate number and size reporting fields. | ||||
|   Use RemoveOnStop for dm-event.socket systemd unit. | ||||
|   Document env var 'DM_DEFAULT_NAME_MANGLING_MODE' in dmsetup man page. | ||||
|   Warn user about incorrect use of cookie with 'dmsetup remove --force'. | ||||
|   Also recognize 'help'/'?' as reserved sort key name to show help. | ||||
|   Add dm_units_to_factor for size unit parsing. | ||||
|   Increase bitset size for minors for thin dmeventd plugin. | ||||
|  | ||||
| Version 1.02.85 - 10th April 2014 | ||||
| ================================= | ||||
|   Check for sprintf error when building internal device path. | ||||
|   Check for sprintf error when creating path for dm control node. | ||||
|   When buffer for dm_get_library_version() is too small, return error code. | ||||
|   Always reinitialize _name_mangling_mode in dm_lib_init(). | ||||
|   Add tracking flag about implicitly added devices into dm_tree. | ||||
|   Stop timeout thread immediately when the last worker thread is finished. | ||||
|   Fix dmeventd logging with parallel wait event processing. | ||||
|   Reuse _node_send_messages() for validation of transaction_id in preload. | ||||
|   Transaction_id could be lower by one only when messages are prepared. | ||||
|   Do not call callback when preload fails. | ||||
|   Wrap is_selinux_enabled() to be called just once. | ||||
|   Use correctly signed 64b constant when working with raid volumes. | ||||
|   Exit dmeventd with pidfile cleanup instead of raising SIGKILL on DIE request. | ||||
|   Add new DM_EVENT_GET_PARAMETERS request to dmeventd protocol. | ||||
|   Do not use systemd's reload for dmeventd restart, use dmeventd -R instead. | ||||
|   Drop cryptsetup rules from 10-dm.rules - cryptsetup >= 1.1.3 sets them. | ||||
|  | ||||
| Version 1.02.84 - 20th January 2014 | ||||
| =================================== | ||||
|   Revert activation of activated nodes if a node preload callback fails. | ||||
|   Avoid busy looping on CPU when dmeventd reads event DM_WAIT_RETRY. | ||||
|   Ensure global mutex is held when working with dmeventd thread. | ||||
|   Drop taking timeout mutex for un/registering dmeventd monitor. | ||||
|   Allow section names in config file data to be quoted strings. | ||||
|   Close fifos before exiting in dmeventd restart() error path. | ||||
|   Move printf format string directly into dm_asprintf args list. | ||||
|   Catch invalid use of string sort values when reporting numerical fields. | ||||
|  | ||||
| Version 1.02.83 - 13th November 2013 | ||||
| ==================================== | ||||
|   Consistently report on stderr when device is not found for dmsetup info. | ||||
|   Skip race errors when non-udev dmsetup build runs on udev-enabled system. | ||||
|   Skip error message when holders are not present in sysfs. | ||||
|   Use __linux__ instead of linux define to make libdevmapper.h C compliant. | ||||
|   Use mutex to avoid possible race while creating/destroying memory pools. | ||||
|   Require libpthread to build now. | ||||
|  | ||||
| Version 1.02.82 - 4th October 2013 | ||||
| ================================== | ||||
|   Define symbolic names for subsystem udev flags in libdevmapper for easier use. | ||||
|   Make subsystem udev rules responsible for importing DM_SUBSYSTEM_UDEV_FLAG*. | ||||
|  | ||||
| Version 1.02.81 - 23rd September 2013 | ||||
| ===================================== | ||||
|   Tidy dmeventd fifo initialisation. | ||||
|  | ||||
| Version 1.02.80 - 20th September 2013 | ||||
| ===================================== | ||||
|   Detect invalid sector supplied to 'dmsetup message'. | ||||
|   Free any previously-set string if a dm_task_set_* function is called again. | ||||
|   Do not allow passing empty new name for dmsetup rename. | ||||
|   Display any output returned by 'dmsetup message'. | ||||
|   Add dm_task_get_message_response to libdevmapper. | ||||
|  | ||||
| Version 1.02.79 - 13th August 2013 | ||||
| ================================== | ||||
|   Create dmeventd timeout threads as "detached" so exit status is freed. | ||||
|   Add DM_ABORT_ON_INTERNAL_ERRORS env var support to abort on internal errors. | ||||
|  | ||||
| Version 1.02.78 - 24th July 2013 | ||||
| ================================ | ||||
|   Process thin messages once to active thin pool target for dm_tree. | ||||
|   Optimize out setting the same value or read_ahead. | ||||
|   Add DM_ARRAY_SIZE public macro. | ||||
|   Move syslog code out of signal handle in dmeventd. | ||||
|   Add DM_TO_STRING public macro. | ||||
|   Always return success on dmeventd -V command call. | ||||
|   Fix parsing of 64bit snapshot status in dmeventd snapshot plugin. | ||||
|   Add dm_get_status_snapshot() for parsing snapshot status. | ||||
|   Detecte mounted fs also via reading /proc/self/mountinfo. | ||||
|   Add dm_mountinfo_read() for parsing /proc/self/mountinfo. | ||||
|   Report error for nonexisting devices in dmeventd communication. | ||||
|   Prevent double free error after dmeventd call of _fill_device_data(). | ||||
|   Update dmevent structure message_data to simplify/fix error path handling. | ||||
|   Validate passed params to dm_get_status_raid/thin/thin_pool().  | ||||
|   Fix 'dmsetup splitname -o' to not fail if used without '-c' switch (1.02.68). | ||||
|   Add dm_config_write_{node_out/one_node_out} for enhanced config output. | ||||
|   Add dm_config_value_is_bool to check for boolean value in supported formats. | ||||
|   Fix config node lookup inside empty sections to not return the section itself. | ||||
|   Append discards and read-only fields to exported struct dm_status_thin_pool. | ||||
|   Fix segfault for truncated string token in config file after the first '"'. | ||||
|   Close open dmeventd FIFO file descriptors on exec (FD_CLOEXEC). | ||||
|   Fix resource leak in error path of dmeventd's umount of thin volume. | ||||
|   Automatically deactivate failed preloaded dm tree node. | ||||
|   Add DM_DISABLE_UDEV environment variable to manage dev nodes by libdm only. | ||||
|   Fix dm_task_set_cookie to properly process udev flags if udev_sync disabled. | ||||
|  | ||||
| Version 1.02.77 - 15th October 2012 | ||||
| =================================== | ||||
|   Support unmount of thin volumes from pool above thin pool threshold. | ||||
|   Update man page to reflect that dm UUIDs are being mangled as well. | ||||
|   Apply 'dmsetup mangle' for dm UUIDs besides dm names. | ||||
|   Add 'mangled_uuid' and 'unmangled_uuid' fields to dmsetup info -c -o. | ||||
|   Mangle device UUID on dm_task_set_uuid/newuuid call if necessary. | ||||
|   Add dm_task_get_uuid_mangled/unmangled to libdevmapper. | ||||
|   Always reset delay_resume_if_new flag when stacking thin pool over anything. | ||||
|   Don't create value for dm_config_node and require dm_config_create_value call. | ||||
|   Check for existing new_name for dmsetup rename. | ||||
|   Fix memory leak in dmsetup _get_split_name() error path. | ||||
|  | ||||
| Version 1.02.76 - 7th August 2012 | ||||
| ================================= | ||||
|   Add dm_vasprintf to libdevmapper. | ||||
|   Allow --noflush with dmsetup status and wait (for thin target). | ||||
|   Add dm_config_write_one_node to libdevmapper. | ||||
|   Support thin pool message release/reserve_metadata_snap in libdevmapper. | ||||
|   Support thin pool discards and external origin features in libdevmapper. | ||||
|   Add configure --enable-udev-rule-exec-detection to detect exec path in rules. | ||||
|   Use sbindir in udev rules by default and remove executable path detection. | ||||
|   Remove hard-coded paths for dmeventd fifos and use default-dm-run-dir. | ||||
|   Add configure --with-lvmetad-pidfile to remove hard-coded value. | ||||
|   Add configure --with-default-pid-dir for common directory with pid files. | ||||
|   Add configure --with-default-dm-run-dir to set run directory for dm tools. | ||||
|   Detect kernel_send() errors in cmirrord. | ||||
|   Add __attribute__ instrumentation to libdevmapper.h. | ||||
|   Print clean_bits instead of sync_bits in pull_state in cmirrord. | ||||
|   Add tests for errors from closedir(), close() in cmirrord. | ||||
|   Add documentation references in systemd units. | ||||
|   Remove veritysetup.  Now maintained with cryptsetup. | ||||
|  | ||||
| Version 1.02.75 - 8th June 2012 | ||||
| =============================== | ||||
|   Upstream source repo now fedorahosted.org git not sources.redhat.com CVS. | ||||
|   Remove unsupported udev_get_dev_path libudev call used for checking udev dir. | ||||
|   Set delay_resume_if_new on deptree snapshot origin. | ||||
|   Log value chosen in _find_config_bool like other variable types do. | ||||
|   Wait for dmeventd to exit after sending it DM_EVENT_CMD_DIE when restarting. | ||||
|   Append 'Used' to {Blk}DevNames/DevNos dmsetup report headers for clarity. | ||||
|   Add configure --with-veritysetup for independent veritysetup tool. | ||||
|   Properly support supplied dmevent path in dm_event_register_handler(). | ||||
|   Remove dmeventd fifos on exit if they are not managed by systemd. | ||||
|   Use SD_ACTIVATION environment variable in systemd units to detect systemd. | ||||
|   Only start a new dmeventd instance on restart if one was already running. | ||||
|   Extend the time waited for input from dmeventd fifo to 5 secs. (1.02.73) | ||||
|  | ||||
| Version 1.02.74 - 6th March 2012 | ||||
| ================================ | ||||
|   Check for multiply-mangled names in auto mangling mode. | ||||
|   Fix dm_task_get_name_unmangled to not unmangle already unmangled name. | ||||
|   Check whether device names are properly mangled on ioctl return. | ||||
|   Deactivation of failed thin check on thin pool returns success. | ||||
|  | ||||
| Version 1.02.73 - 3rd March 2012 | ||||
| ================================ | ||||
|   Test _thread_registry list with holding mutex in dmeventd. | ||||
|   Add dm_tree_node_set_callback() for preload and deactivation hooks. | ||||
|   Drop unsupported TRIM message for thin pool. | ||||
|   Improve logging for fifo startup in dmeventd. | ||||
|   Better detection of missing dmeventd fifo connection (1.02.71). | ||||
|   Add a few pointer validations in dmsetup. | ||||
|   Support dm_task_get_driver_version() query without version string. | ||||
|   Log failure of pthread_join when cleaning unused threads in dmeventd. | ||||
|   Fix empty string warning logic in _find_config_str. (1.02.68) | ||||
|   Fix dm_task_set_name to properly resolve path to dm name (1.02.71). | ||||
|   Add dm_strncpy() function as a faster strncpy() replacement. | ||||
|  | ||||
| Version 1.02.72 - 23rd February 2012 | ||||
| ==================================== | ||||
|   Avoid memory reallocation for dm_asprintf. | ||||
|  | ||||
| Version 1.02.71 - 20th February 2012 | ||||
| ==================================== | ||||
|   Switch to using built-in blkid in 13-dm-disk.rules. | ||||
|   Add "watch" rule to 13-dm-disk.rules. | ||||
|   Detect failing fifo and skip 20s retry communication period. | ||||
|   Add DM_DEFAULT_NAME_MANGLING_MODE environment variable as an override. | ||||
|   Add dm_lib_init to automatically initialise device-mapper library on load. | ||||
|   Replace any '\' char with '\\' in dm table specification on input. | ||||
|   Add mangle command to dmsetup to provide renaming to correct mangled form. | ||||
|   Add 'mangled_name' and 'unmangled_name' fields to dmsetup info -c -o. | ||||
|   Add --manglename option to dmsetup to select the name mangling mode. | ||||
|   Add dm_task_get_name_mangled/unmangled to libdevmapper. | ||||
|   Mangle device name on dm_task_set_name/newname call if necessary. | ||||
|   Add dm_set/get_name_mangling_mode to set/get name mangling in libdevmapper. | ||||
|   Add configure --with-default-name-mangling for udev-friendly dev name charset. | ||||
|   Test for parsed words in _umount() dmeventd snapshot plugin. | ||||
|   Fix memory leak in fail path of parse_loop_device_name() in dmsetup. | ||||
|   Check for missing reply_uuid in dm_event_get_registered_device(). | ||||
|   Check for allocation failure in dmeventd restart(). | ||||
|   Add few missing allocation failures tests in dmsetup. | ||||
|   Fix potential risk of writing in front of buffer in _sysfs_get_dm_name(). | ||||
|  | ||||
| Version 1.02.70 - 12th February 2012 | ||||
| ==================================== | ||||
|   Fix dm_event_get_version() check. | ||||
|   Add pointer test for dependency check in _add_dev(). | ||||
|   Validate name and uuid params of dm_tree_add_new_dev_with_udev_flags(). | ||||
|   Do not crash for dm_report_init() sort_key == NULL and behave like "". | ||||
|   Return error for failing allocation in dm_asprintf(). | ||||
|   Add missing test for failing allocation in dm_realloc() code. | ||||
|   Add test for memory allocation failures in regex matcher code. | ||||
|   Simplify dm_task_set_geometry() and use dm_asprintf(). | ||||
|   Set all parameters to 0 for dm_get_next_target() for NULL return. | ||||
|   Fix fd resource leak in error path for _udev_notify_sem_create(). | ||||
|   Leave space for '\0' for readline() call in _sysfs_get_kernel_name(). | ||||
|  | ||||
| Version 1.02.69 - 1st February 2012 | ||||
| =================================== | ||||
|   Clean up dmeventd systemd unit ordering and requirements. | ||||
|  | ||||
| Version 1.02.68 - 26th January 2012 | ||||
| =================================== | ||||
|   Reset all members of info struct in dm_tree_add_new_dev_with_udev_flags. | ||||
|   Add dmsetup wipe_table to replace table with one that uses error target. | ||||
|   Add 'blkdevname' and 'blkdevs_used' fields to dmsetup info -c -o. | ||||
|   Add 'blkdevname' option to dmsetup ls --tree to see block device names. | ||||
|   Add -o devno/blkdevname/devname to dmsetup deps and ls. | ||||
|   Add dm_device_get_name to get map name or block device name for given devno. | ||||
|   Remove empty devices when clearing left-over inactive tables in deptree. | ||||
|   Add dm_uuid_prefix/dm_set_uuid_prefix to override hard-coded LVM- prefix. | ||||
|   Improve dmsetup man page description of readahead parameter. | ||||
|   Use sysfs to set/get readahead if possible. | ||||
|   Fix lvm2-monitor init script to use normalized output when using vgs. | ||||
|   Add test for max length (DM_MAX_TYPE_NAME) of target type name. | ||||
|   Include a copy of kernel DM documentation in doc/kernel. | ||||
|   Improve man page style for dmsetup and mention more targets. | ||||
|   Fix _get_proc_number to be tolerant of malformed /proc/misc entries. | ||||
|   Fix missing thread list manipulation protection in dmeventd. | ||||
|   Add ExecReload to dm-event.service for systemd to reload dmeventd properly. | ||||
|   Add dm_config_tree_find_str_allow_empty and dm_config_find_str_allow_empty. | ||||
|   Fix compile-time pool memory locking with DEBUG_MEM. | ||||
|   Fix valgrind error reports in free of pool chunks with DEBUG_MEM. | ||||
|   Align size of structure chunk for fast pool allocator to 8 bytes. | ||||
|   Simplify some pointer operations in dm_free_aux() debug code. | ||||
|   Remove unused dbg_malloc.h file from source tree. | ||||
|   Cleanup backtraces for _create_and_load_v4(). | ||||
|   Fix alignment warning in bitcount calculation for raid segment. | ||||
|   Allocate dm_tree structure from dm_tree pool. | ||||
|   Update debug logging for _resume_node. | ||||
|   Add functions to support thin provisioning target. | ||||
|   Improve libdm-config error path reporting. | ||||
|   Update dmsetup resume man with --addnodeonresume/create options. | ||||
|   Add dependency for dm man pages to man subdirectory make all target. | ||||
|   Add dm_tree_retry_remove to use retry logic for device removal in a dm_tree. | ||||
|   Add dm_device_has_mounted_fs fn to check mounted filesystem on a device. | ||||
|   Add dm_device_has_holders fn to to check use of the device by another device. | ||||
|   Add dm_sysfs_dir to libdevmapper to retrieve sysfs location set. | ||||
|   Add dm_set_sysfs_dir to libdevmapper to set sysfs location. | ||||
|   Add --retry option for dmsetup remove to retry removal if not successful. | ||||
|   Add dm_task_retry_remove fn to use retry logic for device removal. | ||||
|   Remove unused passed parameters for _mirror_emit_segment_line(). | ||||
|   Add dm_config and string character escaping functions to libdevmapper. | ||||
|   Mark unreleased memory pools as internal error. | ||||
|  | ||||
| Version 1.02.67 - 19th August 2011 | ||||
| ================================== | ||||
|   Add dm_tree_node_add_null_area for temporarily-missing raid devs tracked. | ||||
|  | ||||
| Version 1.02.66 - 12th August 2011 | ||||
| ================================== | ||||
|   Release geometry buffer in dm_task_destroy. | ||||
|   Update udev rules to skip DM flags decoding for removed devices. | ||||
|   Add compile-time pool memory locking options (to debug shared VG structs). | ||||
|   Remove device name prefix from dmsetup line output if -j & -m or -u supplied. | ||||
|   Remove support for the original version 1 dm ioctls. | ||||
|   Add missing check for allocation failure _create_dir_recursive(). | ||||
|   Add support for systemd file descriptor handover in dmeventd. | ||||
|   Fix memory leak in dmsetup _message() memory allocation error path. | ||||
|   Use new oom killer adjustment interface (oom_score_adj) when available. | ||||
|   Add systemd unit files for dmeventd. | ||||
|   Fix read-only identical table reload supression. | ||||
|  | ||||
| Version 1.02.65 - 8th July 2011 | ||||
| =============================== | ||||
|   Remove dev name prefix from dmsetup line output if exactly one dev requested. | ||||
|   Report internal error if suspending a device using an already-suspended dev. | ||||
|   Report error if a table load requiring target parameters has none supplied. | ||||
|   Add dmsetup --checks and dm_task_enable_checks framework to validate ioctls. | ||||
|   Add age_in_minutes parameter to dmsetup udevcomplete_all. | ||||
|   Return immediately from dm_lib_exit() if called more than once. | ||||
|   Disable udev fallback by default and add --verifyudev option to dmsetup. | ||||
|   Report internal error if any table is loaded while any dev is known suspended. | ||||
|   Add dm_get_suspended_counter() for number of devs in suspended state by lib. | ||||
|   Fix "all" report field prefix matching to include label fields with pv_all. | ||||
|   Delay resuming new preloaded mirror devices with core logs in deptree code. | ||||
|   Accept new kernel version 3 uname formats in initialisation. | ||||
|  | ||||
| Version 1.02.64 - 29th April 2011 | ||||
| ================================== | ||||
|   Require libudev >= 143 when compiling with udev support. | ||||
|   Use word alignment for dm_pool_strdup() and dm_pool_strndup(). | ||||
|   Use dm_snprintf() to fix signedness warning in dm_set_dev_dir(). | ||||
|   Use unsigned loop counter to fix signedness warning in _other_node_ops(). | ||||
|   Fix const cast in dmsetup calls of dm_report_field_string(). | ||||
|   Streamline /dev/mapper/control node code for common cases. | ||||
|   Use hard-coded dm control node device number for 2.6.36 kernels and above. | ||||
|   Improve stack debug reporting in dm_task_create(). | ||||
|   Fallback to control node creation only if node doesn't exist yet. | ||||
|   Change dm_hash binary functions to take void *key instead of char *. | ||||
|   Fix uninitialised memory use with empty params in _reload_with_suppression_v4. | ||||
|   Lower severity of selabel_lookup and matchpathcon failure to log_debug. | ||||
|   Add test for failed allocation from dm_task_set_uuid() in dmeventd. | ||||
|   Add dm_event_get_version to dmeventd for use with -R. | ||||
|   Avoid dmeventd core dumps when handling request with unknown command ID. | ||||
|   Have dmeventd -R start up even when no existing copy is running. | ||||
|   Accept multiple mapped device names on many dmsetup command lines. | ||||
|   Fix dm_udev_wait calls in dmsetup to occur before readahead display not after. | ||||
|   Include an implicit dm_task_update_nodes() within dm_udev_wait(). | ||||
|   Fix _create_and_load_v4 not to lose the --addnodeoncreate setting (1.02.62). | ||||
|   Add inactive table query support for kernel driver >= 4.11.6 (RHEL 5.7). | ||||
|   Log debug open_count in _node_has_closed_parents(). | ||||
|   Add a const to dm_report_field_string() data parameter. | ||||
|  | ||||
| Version 1.02.63 - 9th February 2011 | ||||
| =================================== | ||||
|   Reinstate DEBUG_MEM as it's part of the API. (1.02.62) | ||||
|  | ||||
| Version 1.02.62 - 4th February 2011 | ||||
| =================================== | ||||
|   Add configure --with-device-nodes-on=create for previous behaviour. | ||||
|   Move creation of device nodes from 'create' to 'resume'. | ||||
|   Add --addnodeonresume and --addnodeoncreate options to dmsetup. | ||||
|   Add dm_task_set_add_node to libdevmapper to control dev node creation time. | ||||
|   Add dm_task_secure_data to libdevmapper to wipe ioctl buffers in kernel. | ||||
|   Log debug message when expected uevent is not generated. | ||||
|   Only compile memory debugging code when DEBUG_MEM is set. | ||||
|   Set DM_UDEV_DISABLE_OTHER_RULES_FLAG for suspended DM devices in udev rules. | ||||
|   Begin a new pool object for each row in _output_as_rows() correctly. | ||||
|  | ||||
| Version 1.02.61 - 10th January 2011 | ||||
| =================================== | ||||
|   Add DM_COOKIE_AUTO_CREATE to libdevmapper.h. | ||||
|   Export DM_CONTROL_NODE_UMASK and use it while creating /dev/mapper/control. | ||||
|  | ||||
| Version 1.02.60 - 20th December 2010 | ||||
| ==================================== | ||||
|   Check for unlink failure in remove_lockfile() in dmeventd. | ||||
|   Use dm_free for dm_malloc-ed areas in _clog_ctr/_clog_dtr in cmirrord. | ||||
|   Use char* arithmetic in _process_all() & _targets() in dmsetup. | ||||
|   Change dm_regex_create() API to accept const char * const *patterns. | ||||
|   Add new dm_prepare_selinux_context fn to libdevmapper and use it throughout. | ||||
|   Detect existence of new SELinux selabel interface during configure. | ||||
|  | ||||
| Version 1.02.59 - 6th December 2010 | ||||
| =================================== | ||||
|   Add backtraces to _process_mapper_dir and  _create_and_load_v4 error paths. | ||||
|   Remove superfluous checks for NULL before calling dm_free. | ||||
|  | ||||
| Version 1.02.58 - 22nd November 2010 | ||||
| ==================================== | ||||
|   Fix _output_field crash from field_id free with DEBUG_MEM. (1.02.57) | ||||
|  | ||||
| Version 1.02.57 - 8th November 2010 | ||||
| =================================== | ||||
|   Fix regex optimiser not to ignore RHS of OR nodes in _find_leftmost_common. | ||||
|   Add dmeventd -R to restart dmeventd without losing monitoring state. (1.02.56) | ||||
|   Fix memory leak of field_id in _output_field function. | ||||
|   Allocate buffer for reporting functions dynamically to support long outputs. | ||||
|  | ||||
| Version 1.02.56 - 25th October 2010 | ||||
| =================================== | ||||
|   Return const pointer from dm_basename() in libdevmapper. | ||||
|   Implement dmeventd -R to restart without state loss. | ||||
|   Add dm_zalloc and use it and dm_pool_zalloc throughout. | ||||
|   Add --setuuid to dmsetup rename. | ||||
|   Add dm_task_set_newuuid to set uuid of mapped device post-creation. | ||||
|  | ||||
| Version 1.02.55 - 24th September 2010 | ||||
| ===================================== | ||||
|   Fix the way regions are marked complete to avoid slow --nosync cmirror I/O. | ||||
|   Add DM_REPORT_FIELD_TYPE_ID_LEN to libdevmapper.h. | ||||
|  | ||||
| Version 1.02.54 - 18th August 2010 | ||||
| ================================== | ||||
|   Fix dm-mod autoloading logic to not assume control node is set correctly. | ||||
|   Add dmeventd/executable to lvm.conf to test alternative dmeventd. | ||||
|   Export dm_event_handler_set_dmeventd_path to override built-in dmeventd path. | ||||
|   Generate libdevmapper-event exported symbols. | ||||
|   Remove superfluous NULL pointer tests before dm_free from dmeventd. | ||||
|   Assume dm-mod autoloading support is in kernel 2.6.36 and higher, not 2.6.35. | ||||
|   Fix udev rules to support udev database content generated by older rules. | ||||
|   Reinstate detection of inappropriate uevent with DISK_RO set and suppress it. | ||||
|   Fix regex ttree off-by-one error. | ||||
|   Add --enable-valgrind-pool to configure. | ||||
|   Fix segfault in regex matcher with characters of ordinal value > 127. | ||||
|   Fix 'void*' arithmetic warnings in dbg_malloc.c and libdm-iface.c. | ||||
|   Wait for node creation before displaying debug info in dmsetup. | ||||
|   Fix return status 0 for "dmsetup info -c -o help". | ||||
|   Add check for kernel semaphore support and disable udev_sync if not available. | ||||
|  | ||||
| Version 1.02.53 - 28th July 2010 | ||||
| ================================ | ||||
|   Revert failed table load preparation after "create, load and resume". | ||||
|   Switch dmeventd to use dm_create_lockfile and drop duplicate code. | ||||
|   Add dm_create_lockfile to libdm to handle pidfiles for all daemons. | ||||
|   Replace lookup with next in struct dfa_state & calculate states on demand. | ||||
|   Improve the regex matcher, reducing the number of charset nodes used. | ||||
|   Add dm_regex_fingerprint to facilitate regex testing. | ||||
|   Skip ffs(0) in _test_word in bitset functions. | ||||
|   Use "nowatch" udev rule for inappropriate devices. | ||||
|  | ||||
| Version 1.02.52 - 6th July 2010 | ||||
| =============================== | ||||
|   Fix dmlosetup snprintf %llu compiler warning. | ||||
|   Add parentheses to some libdevmapper.h macro arguments. | ||||
|   Add printf format attributes to dm_{sn,as}printf and fix a caller. | ||||
|   Move dmeventd man page from install_lvm2 to install_device-mapper. (1.02.50) | ||||
|  | ||||
| Version 1.02.51 - 30th June 2010 | ||||
| ================================ | ||||
|   Generate libdevmapper exported symbols from header file. | ||||
|  | ||||
| Version 1.02.50 - 23rd June 2010 | ||||
| ================================ | ||||
|   Fix INTERNAL_ERROR typo in ioctl iface unknown task message. | ||||
|   Fix udev rules to handle spurious events properly. | ||||
|   Use C99 [] not [0] in dm_ulog_request struct to avoid abort when fortified. | ||||
|   Allow use of devmapper header file in C++ mode (extern "C" and __typeof__). | ||||
|   Add dmeventd man page. | ||||
|  | ||||
| Version 1.02.49 - 4th June 2010 | ||||
| =============================== | ||||
|   Support autoloading of dm-mod module for kernels from 2.6.35. | ||||
|   Document 'clear' in dmsetup man page. | ||||
|   Fix semctl parameter (union) to avoid misaligned parameter on some arches. | ||||
|   Add dm_tree_node_set_presuspend_node() to presuspend child when deactivating. | ||||
|   Initial support for replicator target. | ||||
|  | ||||
| Version 1.02.48 - 17th May 2010 | ||||
| ================================ | ||||
|   Use -d to control level of messages sent to syslog by dmeventd. | ||||
|   Change -d to -f to run dmeventd in foreground. | ||||
|   Do not print encryption key in message debug output (cryptsetup luksResume). | ||||
|   Fix dmeventd static build library dependencies. | ||||
|   Fix udev flags on remove in create_and_load error path. | ||||
|  | ||||
| Version 1.02.47 - 30th April 2010 | ||||
| ================================= | ||||
|   Add support for new IMPORT{db} udev rule. | ||||
|   Add DM_UDEV_PRIMARY_SOURCE_FLAG udev flag to recognize proper DM events. | ||||
|   Also include udev libs in libdevmapper.pc when udev_sync is enabled. | ||||
|   Cache bitset locations to speed up _calc_states. | ||||
|   Add a regex optimisation pass for shared prefixes and suffixes. | ||||
|   Add dm_bit_and and dm_bitset_equal to libdevmapper. | ||||
|   Simplify dm_bitset_create. | ||||
|   Speed up dm_bit_get_next with ffs(). | ||||
|  | ||||
| Version 1.02.46 - 14th April 2010 | ||||
| ================================= | ||||
|   Change dm_tree_deactivate_children to fail if device is open. | ||||
|   Wipe memory buffers for dm-ioctl parameters before releasing. | ||||
|   Strictly require libudev if udev_sync is used. | ||||
|   Add support for ioctl's DM_UEVENT_GENERATED_FLAG. | ||||
|  | ||||
| Version 1.02.45 - 9th March 2010 | ||||
| ================================ | ||||
|   Add --showkeys parameter description to dmsetup man page. | ||||
|   Add --help option as synonym for help command. | ||||
|  | ||||
| Version 1.02.44 - 15th February 2010 | ||||
| ==================================== | ||||
|   Add DM_UDEV_DISABLE_LIBRARY_FALLBACK udev flag to rely on udev only. | ||||
|   Export dm_udev_create_cookie function to create new cookies on demand. | ||||
|   Add --udevcookie, udevcreatecookie and udevreleasecookie to dmsetup. | ||||
|   Set udev state automatically instead of using DM_UDEV_DISABLE_CHECKING. | ||||
|  | ||||
| Version 1.02.43 - 21st January 2010 | ||||
| =================================== | ||||
|   Remove bitset, hash and pool headers superceded by libdevmapper.h. | ||||
|   Fix off-by-one error causing bad cluster mirror table construction. | ||||
|  | ||||
| Version 1.02.42 - 14th January 2010 | ||||
| =================================== | ||||
|   Add support for the "snapshot-merge" kernel target (2.6.33-rc1). | ||||
|   Introduce a third activation_priority level in dm_tree_activate_children. | ||||
|  | ||||
| Version 1.02.41 - 12th January 2010 | ||||
| =================================== | ||||
|   If DM_UDEV_DISABLE_CHECKING is set in environment, disable udev warnings. | ||||
|   Add dm_tree_add_dev_with_udev_flags to provide wider support for udev flags. | ||||
|   Add --noudevrules option for dmsetup to disable /dev node management by udev. | ||||
|   Fix 'dmsetup info -c -o all' to show all fields. | ||||
|   Return errors if dm_tree_*_children functions fail. | ||||
|   Fix coredump and memory leak for 'dmsetup help -c'. | ||||
|   Disable udev rules for change events with DISK_RO set. | ||||
|  | ||||
| Version 1.02.40 - 19th November 2009 | ||||
| ==================================== | ||||
|   Fix install_device-mapper Makefile target to not build dmeventd plugins. | ||||
|   Support udev flags even when udev_sync is disabled or not compiled in. | ||||
|   Remove 'last_rule' from udev rules: honour DM_UDEV_DISABLE_OTHER_RULES_FLAG. | ||||
|   Add dmsetup --inactive support. | ||||
|   Add dm_task_query_inactive_table to libdevmapper for kernel driver >= 4.16. | ||||
|   Fix hash lookup segfault when keys compared are different lengths. | ||||
|  | ||||
| Version 1.02.39 - 26th October 2009 | ||||
| =================================== | ||||
|   Remove strict default permissions for DM devices from 95-dm-notify.rules. | ||||
|   Add dmsetup udevflags command to decode udev flags in given cookie value. | ||||
|   Support udev flags in libdevmapper incl. dm_tree_add_new_dev_with_udev_flags. | ||||
|   Make libdm ABI consistent when built with/without selinux support. | ||||
|  | ||||
| Version 1.02.38 - 25th September 2009 | ||||
| ===================================== | ||||
|   Export DM_DEV_DIR_UMASK, the default umask for /dev directories created. | ||||
|   Handle any path supplied to dm_task_set_name by looking up in /dev/mapper. | ||||
|   Add several examples to 12-dm-permissions.rules. | ||||
|   Add splitname and --yes to dmsetup man page. | ||||
|   Fix _mirror_emit_segment_line return code. | ||||
|   Fix dmeventd _temporary_log_fn parameters. (2.02.50) | ||||
|  | ||||
| Version 1.02.37 - 15th September 2009 | ||||
| ===================================== | ||||
|   Add dmsetup manpage entries for udevcomplete_all and udevcookies. | ||||
|   Check udev is running when processing cookies and retain state internally. | ||||
|   Add y|--yes option to dmsetup for default 'yes' answer to prompts. | ||||
|   Fix tools Makefile to process dmsetup sources separately. | ||||
|   Restore umask when device node creation fails. | ||||
|   Check kernel vsn to use 'block_on_error' or 'handle_errors' in mirror table. | ||||
|   Add dm-log-userspace.h to tree for cmirrord builds. | ||||
|  | ||||
| Version 1.02.36 - 6th August 2009 | ||||
| ================================= | ||||
|   Add udevcookies, udevcomplete, udevcomplete_all and --noudevwait to dmsetup. | ||||
|   Add libdevmapper functions to support synchronisation with udev. | ||||
|  | ||||
| Version 1.02.35 - 28th July 2009 | ||||
| ================================ | ||||
|   Add LOG_LINE_WITH_ERRNO macro. | ||||
|   Use log_error macro consistently throughout in place of log_err. | ||||
|  | ||||
| Version 1.02.34 - 15th July 2009 | ||||
| ================================ | ||||
|   Use _exit() not exit() after forking to avoid flushing libc buffers twice. | ||||
|   Rename plog macro to LOG_LINE & add LOG_MESG variant for dm_dump_memory_debug. | ||||
|   Change plog to use dm_log_with_errno unless deprecated dm_log_init was used. | ||||
|   Add dm_log_with_errno and dm_log_with_errno_init, deprecating the old fns. | ||||
|   Fix whitespace in linear target line to fix identical table line detection. | ||||
|   Add device number to more log messages during activation. | ||||
|  | ||||
| Version 1.02.33 - 30th June 2009 | ||||
| ================================ | ||||
|   Don't fallback to default major number: use dm_task_set_major_minor. (1.02.31) | ||||
|   Do not fork daemon when dmeventd cannot be found. | ||||
|   Add crypt target handling to libdevmapper tree nodes. | ||||
|   Add splitname command to dmsetup. | ||||
|   Add subsystem, vg_name, lv_name, lv_layer fields to dmsetup reports. | ||||
|   Make mempool optional in dm_split_lvm_name(). | ||||
|  | ||||
| Version 1.02.32 - 21st May 2009 | ||||
| =============================== | ||||
|   Only generate libdevmapper.a when configured to link statically. | ||||
|   Export dm_tree_node_size_changed() from libdevmapper. | ||||
|   Propagate the table size_changed property up the dm device tree. | ||||
|   Detect failure to free memory pools when releasing the library. | ||||
|   Fix segfault when getopt processes dmsetup -U, -G and -M options. | ||||
|  | ||||
| Version 1.02.31 - 3rd March 2009 | ||||
| ================================ | ||||
|   If kernel supports only one dm major number, use in place of any supplied. | ||||
|  | ||||
| Version 1.02.30 - 26th January 2009 | ||||
| ==================================== | ||||
|   Add "all" field to reports expanding to all fields of report type. | ||||
|   Enforce device name length and character limitations in libdm. | ||||
|   Replace _dm_snprintf with EMIT_PARAMS macro for creating target lines. | ||||
|  | ||||
| Version 1.02.29 - 10th November 2008 | ||||
| ==================================== | ||||
|   Merge device-mapper into the LVM2 tree. | ||||
|   Split out dm-logging.h from log.h. | ||||
|   Use lvm-types.h. | ||||
|   Add usrsbindir to configure. | ||||
|  | ||||
| Version 1.02.28 - 18th September 2008 | ||||
| ===================================== | ||||
|   Only resume devices in dm_tree_preload_children if size changes. | ||||
|   Extend deptree buffers so the largest possible device numbers fit. | ||||
|   Generate versioned libdevmapper-event.so. | ||||
|   Underline longer report help text headings. | ||||
|  | ||||
| Version 1.02.27 - 25th June 2008 | ||||
| ================================ | ||||
|   Align struct memblock in dbg_malloc for sparc. | ||||
|   Add --unquoted and --rows to dmsetup. | ||||
|   Avoid compiler warning about cast in dmsetup.c's OFFSET_OF macro. | ||||
|   Fix inverted no_flush debug message. | ||||
|   Remove --enable-jobs from configure. (Set at runtime instead.) | ||||
|   Bring configure.in and list.h into line with the lvm2 versions. | ||||
|  | ||||
| Version 1.02.26 - 6th June 2008 | ||||
| =============================== | ||||
|   Initialise params buffer to empty string in _emit_segment. | ||||
|   Skip add_dev_node when ioctls disabled. | ||||
|   Make dm_hash_iter safe against deletion. | ||||
|   Accept a NULL pointer to dm_free silently. | ||||
|   Add tables_loaded, readonly and suspended columns to reports. | ||||
|   Add --nameprefixes to dmsetup. | ||||
|   Add field name prefix option to reporting functions. | ||||
|   Calculate string size within dm_pool_grow_object. | ||||
|  | ||||
| Version 1.02.25 - 10th April 2008 | ||||
| ================================= | ||||
|   Remove redundant if-before-free tests. | ||||
|   Use log_warn for reporting field help text instead of log_print. | ||||
|   Change cluster mirror log type name (s/clustered_/clustered-/) | ||||
|  | ||||
| Version 1.02.24 - 20th December 2007 | ||||
| ==================================== | ||||
|   Fix deptree to pass new name to _resume_node after a rename. | ||||
|   Suppress other node operations if node is deleted. | ||||
|   Add node operation stack debug messages. | ||||
|   Report error when empty device name passed to readahead functions. | ||||
|   Fix minimum readahead debug message. | ||||
|  | ||||
| Version 1.02.23 - 5th December 2007 | ||||
| =================================== | ||||
|   Update dm-ioctl.h after removal of compat code. | ||||
|   Add readahead support to libdevmapper and dmsetup. | ||||
|   Fix double free in a libdevmapper-event error path. | ||||
|   Fix configure --with-dmeventd-path substitution. | ||||
|   Allow a DM_DEV_DIR environment variable to override /dev in dmsetup. | ||||
|   Create a libdevmapper.so.$LIB_VERSION symlink within the build tree. | ||||
|   Avoid static link failure with some SELinux libraries that require libpthread. | ||||
|   Remove obsolete dmfs code from tree and update INSTALL. | ||||
|  | ||||
| Version 1.02.22 - 21st August 2007 | ||||
| ================================== | ||||
|   Fix inconsistent licence notices: executables are GPLv2; libraries LGPLv2.1. | ||||
|   Update to use autoconf 2.61, while still supporting 2.57. | ||||
|   Avoid repeated dm_task free on some dm_event_get_registered_device errors. | ||||
|   Introduce log_sys_* macros from LVM2. | ||||
|   Export dm_fclose and dm_create_dir; remove libdm-file.h. | ||||
|   Don't log EROFS mkdir failures in _create_dir_recursive (for LVM2). | ||||
|   Add fclose wrapper dm_fclose that catches write failures (using ferror). | ||||
|  | ||||
| Version 1.02.21 - 13th July 2007 | ||||
| ================================ | ||||
|   Introduce _LOG_STDERR to send log_warn() messages to stderr not stdout. | ||||
|   Fix dmsetup -o devno string termination. (1.02.20) | ||||
|  | ||||
| Version 1.02.20 - 15th June 2007 | ||||
| ================================ | ||||
|   Fix default dmsetup report buffering and add --unbuffered. | ||||
|   Add tree-based and dependency fields to dmsetup reports. | ||||
|  | ||||
| Version 1.02.19 - 27th April 2007 | ||||
| ================================= | ||||
|   Standardise protective include file #defines. | ||||
|   Add regex functions to library. | ||||
|   Avoid trailing separator in reports when there are hidden sort fields. | ||||
|   Fix segfault in 'dmsetup status' without --showkeys against crypt target. | ||||
|   Deal with some more compiler warnings. | ||||
|   Introduce _add_field() and _is_same_field() to libdm-report.c. | ||||
|   Fix some libdevmapper-event and dmeventd memory leaks. | ||||
|   Remove unnecessary memset() return value checks. | ||||
|   Fix a few leaks in reporting error paths. [1.02.15+] | ||||
|  | ||||
| Version 1.02.18 - 13th February 2007 | ||||
| ==================================== | ||||
|   Improve dmeventd messaging protocol: drain pipe and tag messages. | ||||
|  | ||||
| Version 1.02.17 - 29th January 2007 | ||||
| =================================== | ||||
|   Add recent reporting options to dmsetup man page. | ||||
|   Revise some report fields names. | ||||
|   Add dmsetup 'help' command and update usage text. | ||||
|   Use fixed-size fields in report interface and reorder. | ||||
|  | ||||
| Version 1.02.16 - 25th January 2007 | ||||
| =================================== | ||||
|   Add some missing close() and fclose() return value checks. | ||||
|   Migrate dmsetup column-based output over to new libdevmapper report framework. | ||||
|   Add descriptions to reporting field definitions. | ||||
|   Add a dso-private variable to dmeventd dso interface. | ||||
|   Add dm_event_handler_[gs]et_timeout functions. | ||||
|   Streamline dm_report_field_* interface. | ||||
|   Add cmdline debug & version options to dmeventd. | ||||
|   Add DM_LIB_VERSION definition to configure.h. | ||||
|   Suppress 'Unrecognised field' error if report field is 'help'. | ||||
|   Add --separator and --sort to dmsetup (unused). | ||||
|   Make alignment flag optional when specifying report fields. | ||||
|  | ||||
| Version 1.02.15 - 17th January 2007 | ||||
| =================================== | ||||
|   Add basic reporting functions to libdevmapper. | ||||
|   Fix a malloc error path in dmsetup message. | ||||
|   More libdevmapper-event interface changes and fixes. | ||||
|   Rename dm_saprintf() to dm_asprintf(). | ||||
|   Report error if NULL pointer is supplied to dm_strdup_aux(). | ||||
|   Reinstate dm_event_get_registered_device. | ||||
|  | ||||
| Version 1.02.14 - 11th January 2007 | ||||
| =================================== | ||||
|   Add dm_saprintf(). | ||||
|   Use CFLAGS when linking so mixed sparc builds can supply -m64. | ||||
|   Add dm_tree_use_no_flush_suspend(). | ||||
|   Lots of dmevent changes including revised interface. | ||||
|   Export dm_basename(). | ||||
|   Cope with a trailing space when comparing tables prior to possible reload. | ||||
|   Fix dmeventd to cope if monitored device disappears. | ||||
|  | ||||
| Version 1.02.13 - 28 Nov 2006 | ||||
| Version 1.00.18 | ||||
| ============================= | ||||
|   Update dmsetup man page (setgeometry & message). | ||||
|   Fix dmsetup free after getline with debug. | ||||
|   Suppress encryption key in 'dmsetup table' output unless --showkeys supplied. | ||||
|  | ||||
| Version 1.02.12 - 13 Oct 2006 | ||||
| ============================= | ||||
|   Avoid deptree attempting to suspend a device that's already suspended. | ||||
|  | ||||
| Version 1.02.11 -  12 Oct 2006 | ||||
| ============================== | ||||
|   Add suspend noflush support. | ||||
|   Add basic dmsetup loop support. | ||||
|   Switch dmsetup to use dm_malloc and dm_free. | ||||
|  | ||||
| Version 1.02.10 - 19 Sep 2006 | ||||
| ============================= | ||||
|   Add dm_snprintf(), dm_split_words() and dm_split_lvm_name() to libdevmapper. | ||||
|   Reorder mm bounds_check code to reduce window for a dmeventd race. | ||||
|  | ||||
| Version 1.02.09 - 15 Aug 2006 | ||||
| ============================= | ||||
|   Add --table argument to dmsetup for a one-line table. | ||||
|   Abort if errors are found during cmdline option processing. | ||||
|   Add lockfs indicator to debug output. | ||||
|  | ||||
| Version 1.02.08 - 17 July 2006 | ||||
| ============================== | ||||
|   Append full patch to check in emails. | ||||
|   Avoid duplicate dmeventd subdir with 'make distclean'. | ||||
|   Update dmsetup man page. | ||||
|   Add --force to dmsetup remove* to load error target. | ||||
|   dmsetup remove_all also performs mknodes. | ||||
|   Don't suppress identical table reloads if permission changes. | ||||
|   Fix corelog segment line. | ||||
|   Suppress some compiler warnings. | ||||
|  | ||||
| Version 1.02.07 - 11 May 2006 | ||||
| ============================= | ||||
|   Add DM_CORELOG flag to dm_tree_node_add_mirror_target(). | ||||
|   Avoid a dmeventd compiler warning. | ||||
|  | ||||
| Version 1.02.06 - 10 May 2006 | ||||
| ============================= | ||||
|   Move DEFS into configure.h. | ||||
|   Fix leaks in error paths found by coverity. | ||||
|   Remove dmsetup line buffer limitation. | ||||
|  | ||||
| Version 1.02.05 - 19 Apr 2006 | ||||
| ============================= | ||||
|   Separate install_include target in makefiles. | ||||
|   Separate out DEFS from CFLAGS. | ||||
|   Support pkg-config. | ||||
|   Check for libsepol. | ||||
|  | ||||
| Version 1.02.04 - 14 Apr 2006 | ||||
| ============================= | ||||
|   Bring dmsetup man page up-to-date. | ||||
|   Use name-based device refs if kernel doesn't support device number refs. | ||||
|   Fix memory leak (struct dm_ioctl) when struct dm_task is reused. | ||||
|   If _create_and_load_v4 fails part way through, revert the creation. | ||||
|   dmeventd thread/fifo fixes. | ||||
|   Add file & line to dm_strdup_aux(). | ||||
|   Add setgeometry. | ||||
|  | ||||
| Version 1.02.03 - 7 Feb 2006 | ||||
| ============================ | ||||
|   Add exported functions to set uid, gid and mode. | ||||
|   Rename _log to dm_log and export. | ||||
|   Add dm_tree_skip_lockfs. | ||||
|   Fix dm_strdup debug definition. | ||||
|   Fix hash function to avoid using a negative array offset. | ||||
|   Don't inline _find in hash.c and tidy signed/unsigned etc. | ||||
|   Fix libdevmapper.h #endif. | ||||
|   Fix dmsetup version driver version. | ||||
|   Add sync, nosync and block_on_error mirror log parameters. | ||||
|   Add hweight32. | ||||
|   Fix dmeventd build. | ||||
|  | ||||
| Version 1.02.02 - 2 Dec 2005 | ||||
| ============================ | ||||
|   dmeventd added. | ||||
|   Export dm_task_update_nodes. | ||||
|   Use names instead of numbers in messages when ioctls fail. | ||||
|  | ||||
| Version 1.02.01 - 23 Nov 2005 | ||||
| ============================= | ||||
|   Resume snapshot-origins last. | ||||
|   Drop leading zeros from dm_format_dev. | ||||
|   Suppress attempt to reload identical table. | ||||
|   Additional LVM- prefix matching for transitional period. | ||||
|  | ||||
| Version 1.02.00 - 10 Nov 2005 | ||||
| ============================= | ||||
|   Added activation functions to library. | ||||
|   Added return macros. | ||||
|   Also suppress error if device doesn't exist with DM_DEVICE_STATUS. | ||||
|   Export dm_set_selinux_context(). | ||||
|   Add dm_driver_version(). | ||||
|   Added dependency tree functions to library. | ||||
|   Added hash, bitset, pool, dbg_malloc to library. | ||||
|   Added ls --tree to dmsetup. | ||||
|   Added dmsetup --nolockfs support for suspend/reload. | ||||
|  | ||||
| Version 1.01.05 - 26 Sep 2005 | ||||
| ============================= | ||||
|   Resync list.h with LVM2. | ||||
|   Remember increased buffer size and use for subsequent calls. | ||||
|   On 'buffer full' condition, double buffer size and repeat ioctl. | ||||
|   Fix termination of getopt_long() option array. | ||||
|   Report 'buffer full' condition with v4 ioctl as well as with v1. | ||||
|  | ||||
| Version 1.01.04 - 2 Aug 2005 | ||||
| ============================ | ||||
|   Fix dmsetup ls -j and status --target with empty table. | ||||
|  | ||||
| Version 1.01.03 - 13 Jun 2005 | ||||
| ============================= | ||||
|   Use matchpathcon mode parameter. | ||||
|   Fix configure script to re-enable selinux. | ||||
|  | ||||
| Version 1.01.02 - 17 May 2005 | ||||
| ============================= | ||||
|   Call dm_lib_exit() and dm_lib_release() automatically now. | ||||
|   Add --target <target_type> filter to dmsetup table/status/ls. | ||||
|   Add --exec <command> to dmsetup ls. | ||||
|   Fix dmsetup getopt_long usage. | ||||
|  | ||||
| Version 1.01.01 - 29 Mar 2005 | ||||
| ============================= | ||||
|   Update dmsetup man page. | ||||
|   Drop-in devmap_name replacement. | ||||
|   Add option to compile without ioctl for testing. | ||||
|   Fix DM_LIB_VERSION sed. | ||||
|  | ||||
| Version 1.01.00 - 17 Jan 2005 | ||||
| ============================= | ||||
|   Add dm_task_no_open_count() to skip getting open_count. | ||||
|  | ||||
| Version 1.00.21 - 7 Jan 2005 | ||||
| ============================ | ||||
|   Fix /proc/devices parsing. | ||||
|  | ||||
| Version 1.00.20 - 6 Jan 2005 | ||||
| ============================ | ||||
|   Attempt to fix /dev/mapper/control transparently if it's wrong. | ||||
|   Configuration-time option for setting uid/gid/mode for /dev/mapper nodes. | ||||
|   Update kernel patches for 2.4.27/2.4.28-pre-4 (includes minor fixes). | ||||
|   Add --noheadings columns option for colon-separated dmsetup output. | ||||
|   Support device referencing by uuid or major/minor. | ||||
|   Warn if kernel data didn't fit in buffer. | ||||
|   Fix a printf. | ||||
|  | ||||
| Version 1.00.19 - 3 July 2004 | ||||
| ============================= | ||||
|   More autoconf fixes. | ||||
|   Fix a dmsetup newline. | ||||
|   Fix device number handling for 2.6 kernels. | ||||
|  | ||||
| Version 1.00.18 - 20 Jun 2004 | ||||
| ============================= | ||||
|   Fix a uuid free in libdm-iface. | ||||
|   Fix a targets string size calc in driver. | ||||
|   Add -c to dmsetup for column-based output. | ||||
|   Add target message-passing ioctl. | ||||
|  | ||||
| Version 1.00.17 - 17 Apr 2004 | ||||
| @@ -969,3 +60,4 @@ Version 1.00.08 - 27 Feb 2004 | ||||
|   Fixed DESTDIR for make install/install_static_lib. | ||||
|   Updated README/INSTALL to reflect move to sources.redhat.com. | ||||
|   Updated autoconf files to 2003-06-17. | ||||
|  | ||||
|   | ||||
							
								
								
									
										59
									
								
								acinclude.m4
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								acinclude.m4
									
									
									
									
									
								
							| @@ -1,59 +0,0 @@ | ||||
| dnl AC_GCC_VERSION | ||||
| dnl check for compiler version | ||||
| dnl sets COMPILER_VERSION and GCC_VERSION | ||||
|  | ||||
| AC_DEFUN([AC_CC_VERSION], | ||||
| [ | ||||
|     AC_MSG_CHECKING([C compiler version]) | ||||
|     COMPILER_VERSION=`$CC -v 2>&1 | grep version` | ||||
|     case "$COMPILER_VERSION" in | ||||
|         *gcc*) | ||||
| 	   dnl Ok, how to turn $3 into the real $3 | ||||
| 	   GCC_VERSION=`echo $COMPILER_VERSION | \ | ||||
| 	   sed -e 's/[[^ ]]*\ [[^ ]]*\ \([[^ ]]*\)\ .*/\1/'` ;; | ||||
| 	*) GCC_VERSION=unknown ;; | ||||
|     esac | ||||
|     AC_MSG_RESULT($GCC_VERSION) | ||||
| ]) | ||||
|  | ||||
| dnl AC_TRY_CCFLAG([CCFLAG], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS]) | ||||
| dnl check if $CC supports a given flag | ||||
|  | ||||
| AC_DEFUN([AC_TRY_CCFLAG], | ||||
| [ | ||||
|     AC_REQUIRE([AC_PROG_CC]) | ||||
|     ac_save_CFLAGS=$CFLAGS | ||||
|     CFLAGS=$1 | ||||
|     AC_CACHE_CHECK([whether $CC accepts $1 flag], [ac_cv_flag_$2], | ||||
| 	[AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], | ||||
| 			   [AS_VAR_SET([ac_cv_flag_$2], [yes])], | ||||
| 			   [AS_VAR_SET([ac_cv_flag_$2], [no])])]) | ||||
|     CFLAGS=$ac_save_CFLAGS | ||||
|     $2=AS_VAR_GET([ac_cv_flag_$2]) | ||||
|     if test "$2" = yes; then | ||||
|         ifelse([$3], [], [:], [$3]) | ||||
|     else | ||||
|         ifelse([$4], [], [:], [$4]) | ||||
|     fi | ||||
| ]) | ||||
|  | ||||
| dnl AC_TRY_LDFLAGS([LDFLAGS], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS]) | ||||
| dnl check if $CC supports given ld flags | ||||
|  | ||||
| AC_DEFUN([AC_TRY_LDFLAGS], | ||||
| [ | ||||
|     AC_REQUIRE([AC_PROG_CC]) | ||||
|     ac_save_LDFLAGS=$LDFLAGS | ||||
|     LDFLAGS=$1 | ||||
| 	AC_CACHE_CHECK([whether $CC accepts $1 ld flags], [ac_cv_flag_$2], | ||||
| 	[AC_LINK_IFELSE([AC_LANG_PROGRAM()], | ||||
| 			[AS_VAR_SET([ac_cv_flag_$2], [yes])], | ||||
| 			[AS_VAR_SET([ac_cv_flag_$2], [no])])]) | ||||
|     LDFLAGS=$ac_save_LDFLAGS | ||||
|     $2=AS_VAR_GET([ac_cv_flag_$2]) | ||||
|     if test "$2" = yes; then | ||||
|         ifelse([$3], [], [:], [$3]) | ||||
|     else | ||||
|         ifelse([$4], [], [:], [$4]) | ||||
|     fi | ||||
| ]) | ||||
							
								
								
									
										230
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										230
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							| @@ -1,230 +0,0 @@ | ||||
| # generated automatically by aclocal 1.13.4 -*- Autoconf -*- | ||||
|  | ||||
| # Copyright (C) 1996-2013 Free Software Foundation, Inc. | ||||
|  | ||||
| # This file is free software; the Free Software Foundation | ||||
| # gives unlimited permission to copy and/or distribute it, | ||||
| # with or without modifications, as long as this notice is preserved. | ||||
|  | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY, to the extent permitted by law; without | ||||
| # even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||||
| # PARTICULAR PURPOSE. | ||||
|  | ||||
| m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) | ||||
| # pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*- | ||||
| # serial 1 (pkg-config-0.24) | ||||
| #  | ||||
| # Copyright © 2004 Scott James Remnant <scott@netsplit.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 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # 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, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| # | ||||
| # As a special exception to the GNU General Public License, if you | ||||
| # distribute this file as part of a program that contains a | ||||
| # configuration script generated by Autoconf, you may include it under | ||||
| # the same distribution terms that you use for the rest of that program. | ||||
|  | ||||
| # PKG_PROG_PKG_CONFIG([MIN-VERSION]) | ||||
| # ---------------------------------- | ||||
| AC_DEFUN([PKG_PROG_PKG_CONFIG], | ||||
| [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) | ||||
| m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) | ||||
| m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) | ||||
| AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) | ||||
| AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) | ||||
| AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) | ||||
|  | ||||
| if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then | ||||
| 	AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) | ||||
| fi | ||||
| if test -n "$PKG_CONFIG"; then | ||||
| 	_pkg_min_version=m4_default([$1], [0.9.0]) | ||||
| 	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) | ||||
| 	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then | ||||
| 		AC_MSG_RESULT([yes]) | ||||
| 	else | ||||
| 		AC_MSG_RESULT([no]) | ||||
| 		PKG_CONFIG="" | ||||
| 	fi | ||||
| fi[]dnl | ||||
| ])# PKG_PROG_PKG_CONFIG | ||||
|  | ||||
| # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| # | ||||
| # Check to see whether a particular set of modules exists.  Similar | ||||
| # to PKG_CHECK_MODULES(), but does not set variables or print errors. | ||||
| # | ||||
| # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) | ||||
| # only at the first occurence in configure.ac, so if the first place | ||||
| # it's called might be skipped (such as if it is within an "if", you | ||||
| # have to call PKG_CHECK_EXISTS manually | ||||
| # -------------------------------------------------------------- | ||||
| AC_DEFUN([PKG_CHECK_EXISTS], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| if test -n "$PKG_CONFIG" && \ | ||||
|     AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then | ||||
|   m4_default([$2], [:]) | ||||
| m4_ifvaln([$3], [else | ||||
|   $3])dnl | ||||
| fi]) | ||||
|  | ||||
| # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) | ||||
| # --------------------------------------------- | ||||
| m4_define([_PKG_CONFIG], | ||||
| [if test -n "$$1"; then | ||||
|     pkg_cv_[]$1="$$1" | ||||
|  elif test -n "$PKG_CONFIG"; then | ||||
|     PKG_CHECK_EXISTS([$3], | ||||
|                      [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` | ||||
| 		      test "x$?" != "x0" && pkg_failed=yes ], | ||||
| 		     [pkg_failed=yes]) | ||||
|  else | ||||
|     pkg_failed=untried | ||||
| fi[]dnl | ||||
| ])# _PKG_CONFIG | ||||
|  | ||||
| # _PKG_SHORT_ERRORS_SUPPORTED | ||||
| # ----------------------------- | ||||
| AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) | ||||
| if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then | ||||
|         _pkg_short_errors_supported=yes | ||||
| else | ||||
|         _pkg_short_errors_supported=no | ||||
| fi[]dnl | ||||
| ])# _PKG_SHORT_ERRORS_SUPPORTED | ||||
|  | ||||
|  | ||||
| # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], | ||||
| # [ACTION-IF-NOT-FOUND]) | ||||
| # | ||||
| # | ||||
| # Note that if there is a possibility the first call to | ||||
| # PKG_CHECK_MODULES might not happen, you should be sure to include an | ||||
| # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac | ||||
| # | ||||
| # | ||||
| # -------------------------------------------------------------- | ||||
| AC_DEFUN([PKG_CHECK_MODULES], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl | ||||
| AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl | ||||
|  | ||||
| pkg_failed=no | ||||
| AC_MSG_CHECKING([for $1]) | ||||
|  | ||||
| _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) | ||||
| _PKG_CONFIG([$1][_LIBS], [libs], [$2]) | ||||
|  | ||||
| m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS | ||||
| and $1[]_LIBS to avoid the need to call pkg-config. | ||||
| See the pkg-config man page for more details.]) | ||||
|  | ||||
| if test $pkg_failed = yes; then | ||||
|    	AC_MSG_RESULT([no]) | ||||
|         _PKG_SHORT_ERRORS_SUPPORTED | ||||
|         if test $_pkg_short_errors_supported = yes; then | ||||
| 	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` | ||||
|         else  | ||||
| 	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` | ||||
|         fi | ||||
| 	# Put the nasty error message in config.log where it belongs | ||||
| 	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD | ||||
|  | ||||
| 	m4_default([$4], [AC_MSG_ERROR( | ||||
| [Package requirements ($2) were not met: | ||||
|  | ||||
| $$1_PKG_ERRORS | ||||
|  | ||||
| Consider adjusting the PKG_CONFIG_PATH environment variable if you | ||||
| installed software in a non-standard prefix. | ||||
|  | ||||
| _PKG_TEXT])[]dnl | ||||
|         ]) | ||||
| elif test $pkg_failed = untried; then | ||||
|      	AC_MSG_RESULT([no]) | ||||
| 	m4_default([$4], [AC_MSG_FAILURE( | ||||
| [The pkg-config script could not be found or is too old.  Make sure it | ||||
| is in your PATH or set the PKG_CONFIG environment variable to the full | ||||
| path to pkg-config. | ||||
|  | ||||
| _PKG_TEXT | ||||
|  | ||||
| To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl | ||||
|         ]) | ||||
| else | ||||
| 	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS | ||||
| 	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS | ||||
|         AC_MSG_RESULT([yes]) | ||||
| 	$3 | ||||
| fi[]dnl | ||||
| ])# PKG_CHECK_MODULES | ||||
|  | ||||
|  | ||||
| # PKG_INSTALLDIR(DIRECTORY) | ||||
| # ------------------------- | ||||
| # Substitutes the variable pkgconfigdir as the location where a module | ||||
| # should install pkg-config .pc files. By default the directory is | ||||
| # $libdir/pkgconfig, but the default can be changed by passing | ||||
| # DIRECTORY. The user can override through the --with-pkgconfigdir | ||||
| # parameter. | ||||
| AC_DEFUN([PKG_INSTALLDIR], | ||||
| [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) | ||||
| m4_pushdef([pkg_description], | ||||
|     [pkg-config installation directory @<:@]pkg_default[@:>@]) | ||||
| AC_ARG_WITH([pkgconfigdir], | ||||
|     [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, | ||||
|     [with_pkgconfigdir=]pkg_default) | ||||
| AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) | ||||
| m4_popdef([pkg_default]) | ||||
| m4_popdef([pkg_description]) | ||||
| ]) dnl PKG_INSTALLDIR | ||||
|  | ||||
|  | ||||
| # PKG_NOARCH_INSTALLDIR(DIRECTORY) | ||||
| # ------------------------- | ||||
| # Substitutes the variable noarch_pkgconfigdir as the location where a | ||||
| # module should install arch-independent pkg-config .pc files. By | ||||
| # default the directory is $datadir/pkgconfig, but the default can be | ||||
| # changed by passing DIRECTORY. The user can override through the | ||||
| # --with-noarch-pkgconfigdir parameter. | ||||
| AC_DEFUN([PKG_NOARCH_INSTALLDIR], | ||||
| [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) | ||||
| m4_pushdef([pkg_description], | ||||
|     [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) | ||||
| AC_ARG_WITH([noarch-pkgconfigdir], | ||||
|     [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, | ||||
|     [with_noarch_pkgconfigdir=]pkg_default) | ||||
| AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) | ||||
| m4_popdef([pkg_default]) | ||||
| m4_popdef([pkg_description]) | ||||
| ]) dnl PKG_NOARCH_INSTALLDIR | ||||
|  | ||||
|  | ||||
| # PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, | ||||
| # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||||
| # ------------------------------------------- | ||||
| # Retrieves the value of the pkg-config variable for the given module. | ||||
| AC_DEFUN([PKG_CHECK_VAR], | ||||
| [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||||
| AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl | ||||
|  | ||||
| _PKG_CONFIG([$1], [variable="][$3]["], [$2]) | ||||
| AS_VAR_COPY([$1], [pkg_cv_][$1]) | ||||
|  | ||||
| AS_VAR_IF([$1], [""], [$5], [$4])dnl | ||||
| ])# PKG_CHECK_VAR | ||||
|  | ||||
| m4_include([acinclude.m4]) | ||||
							
								
								
									
										1120
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1120
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										531
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										531
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							| @@ -1,40 +1,42 @@ | ||||
| #! /bin/sh | ||||
| # Configuration validation subroutine script. | ||||
| #   Copyright 1992-2014 Free Software Foundation, Inc. | ||||
| #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, | ||||
| #   2000, 2001, 2002, 2003 Free Software Foundation, Inc. | ||||
|  | ||||
| timestamp='2014-01-01' | ||||
| timestamp='2003-06-17' | ||||
|  | ||||
| # This file 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 3 of the License, or | ||||
| # This file is (in principle) common to ALL GNU software. | ||||
| # The presence of a machine in this file suggests that SOME GNU software | ||||
| # can handle that machine.  It does not imply ALL GNU software can. | ||||
| # | ||||
| # This file 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. | ||||
| # | ||||
| # 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. | ||||
| # 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/>. | ||||
| # | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place - Suite 330, | ||||
| # Boston, MA 02111-1307, USA. | ||||
|  | ||||
| # As a special exception to the GNU General Public License, if you | ||||
| # distribute this file as part of a program that contains a | ||||
| # configuration script generated by Autoconf, you may include it under | ||||
| # the same distribution terms that you use for the rest of that | ||||
| # program.  This Exception is an additional permission under section 7 | ||||
| # of the GNU General Public License, version 3 ("GPLv3"). | ||||
| # the same distribution terms that you use for the rest of that program. | ||||
|  | ||||
|  | ||||
| # Please send patches with a ChangeLog entry to config-patches@gnu.org. | ||||
| # Please send patches to <config-patches@gnu.org>.  Submit a context | ||||
| # diff and a properly formatted ChangeLog entry. | ||||
| # | ||||
| # Configuration subroutine to validate and canonicalize a configuration type. | ||||
| # Supply the specified configuration type as an argument. | ||||
| # If it is invalid, we print an error message on stderr and exit with code 1. | ||||
| # Otherwise, we print the canonical config type on stdout and succeed. | ||||
|  | ||||
| # You can get the latest version of this script from: | ||||
| # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD | ||||
|  | ||||
| # This file is supposed to be the same for all GNU packages | ||||
| # and recognize all the CPU types, system types and aliases | ||||
| # that are meaningful with *any* GNU software. | ||||
| @@ -68,7 +70,8 @@ Report bugs and patches to <config-patches@gnu.org>." | ||||
| version="\ | ||||
| GNU config.sub ($timestamp) | ||||
|  | ||||
| Copyright 1992-2014 Free Software Foundation, Inc. | ||||
| Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 | ||||
| Free Software Foundation, Inc. | ||||
|  | ||||
| This is free software; see the source for copying conditions.  There is NO | ||||
| warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." | ||||
| @@ -80,11 +83,11 @@ Try \`$me --help' for more information." | ||||
| while test $# -gt 0 ; do | ||||
|   case $1 in | ||||
|     --time-stamp | --time* | -t ) | ||||
|        echo "$timestamp" ; exit ;; | ||||
|        echo "$timestamp" ; exit 0 ;; | ||||
|     --version | -v ) | ||||
|        echo "$version" ; exit ;; | ||||
|        echo "$version" ; exit 0 ;; | ||||
|     --help | --h* | -h ) | ||||
|        echo "$usage"; exit ;; | ||||
|        echo "$usage"; exit 0 ;; | ||||
|     -- )     # Stop option processing | ||||
|        shift; break ;; | ||||
|     - )	# Use stdin as input. | ||||
| @@ -96,7 +99,7 @@ while test $# -gt 0 ; do | ||||
|     *local*) | ||||
|        # First pass through any local machine types. | ||||
|        echo $1 | ||||
|        exit ;; | ||||
|        exit 0;; | ||||
|  | ||||
|     * ) | ||||
|        break ;; | ||||
| @@ -115,18 +118,10 @@ esac | ||||
| # Here we must recognize all the valid KERNEL-OS combinations. | ||||
| maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` | ||||
| case $maybe_os in | ||||
|   nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ | ||||
|   linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ | ||||
|   knetbsd*-gnu* | netbsd*-gnu* | \ | ||||
|   kopensolaris*-gnu* | \ | ||||
|   storm-chaos* | os2-emx* | rtmk-nova*) | ||||
|   nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) | ||||
|     os=-$maybe_os | ||||
|     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` | ||||
|     ;; | ||||
|   android-linux) | ||||
|     os=-linux-android | ||||
|     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown | ||||
|     ;; | ||||
|   *) | ||||
|     basic_machine=`echo $1 | sed 's/-[^-]*$//'` | ||||
|     if [ $basic_machine != $1 ] | ||||
| @@ -149,13 +144,10 @@ case $os in | ||||
| 	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ | ||||
| 	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ | ||||
| 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ | ||||
| 	-apple | -axis | -knuth | -cray | -microblaze*) | ||||
| 	-apple | -axis) | ||||
| 		os= | ||||
| 		basic_machine=$1 | ||||
| 		;; | ||||
| 	-bluegene*) | ||||
| 		os=-cnk | ||||
| 		;; | ||||
| 	-sim | -cisco | -oki | -wec | -winbond) | ||||
| 		os= | ||||
| 		basic_machine=$1 | ||||
| @@ -170,17 +162,13 @@ case $os in | ||||
| 		os=-chorusos | ||||
| 		basic_machine=$1 | ||||
| 		;; | ||||
| 	-chorusrdb) | ||||
| 		os=-chorusrdb | ||||
|  	-chorusrdb) | ||||
|  		os=-chorusrdb | ||||
| 		basic_machine=$1 | ||||
| 		;; | ||||
|  		;; | ||||
| 	-hiux*) | ||||
| 		os=-hiuxwe2 | ||||
| 		;; | ||||
| 	-sco6) | ||||
| 		os=-sco5v6 | ||||
| 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | ||||
| 		;; | ||||
| 	-sco5) | ||||
| 		os=-sco3.2v5 | ||||
| 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | ||||
| @@ -197,10 +185,6 @@ case $os in | ||||
| 		# Don't forget version if it is 3.2v4 or newer. | ||||
| 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | ||||
| 		;; | ||||
| 	-sco5v6*) | ||||
| 		# Don't forget version if it is 3.2v4 or newer. | ||||
| 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | ||||
| 		;; | ||||
| 	-sco*) | ||||
| 		os=-sco3.2v2 | ||||
| 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | ||||
| @@ -218,12 +202,6 @@ case $os in | ||||
| 	-isc*) | ||||
| 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` | ||||
| 		;; | ||||
| 	-lynx*178) | ||||
| 		os=-lynxos178 | ||||
| 		;; | ||||
| 	-lynx*5) | ||||
| 		os=-lynxos5 | ||||
| 		;; | ||||
| 	-lynx*) | ||||
| 		os=-lynxos | ||||
| 		;; | ||||
| @@ -248,107 +226,55 @@ case $basic_machine in | ||||
| 	# Some are omitted here because they have special meanings below. | ||||
| 	1750a | 580 \ | ||||
| 	| a29k \ | ||||
| 	| aarch64 | aarch64_be \ | ||||
| 	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | ||||
| 	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | ||||
| 	| am33_2.0 \ | ||||
| 	| arc | arceb \ | ||||
| 	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | ||||
| 	| avr | avr32 \ | ||||
| 	| be32 | be64 \ | ||||
| 	| bfin \ | ||||
| 	| c4x | c8051 | clipper \ | ||||
| 	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | ||||
| 	| c4x | clipper \ | ||||
| 	| d10v | d30v | dlx | dsp16xx \ | ||||
| 	| epiphany \ | ||||
| 	| fido | fr30 | frv \ | ||||
| 	| fr30 | frv \ | ||||
| 	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | ||||
| 	| hexagon \ | ||||
| 	| i370 | i860 | i960 | ia64 \ | ||||
| 	| ip2k | iq2000 \ | ||||
| 	| k1om \ | ||||
| 	| le32 | le64 \ | ||||
| 	| lm32 \ | ||||
| 	| m32c | m32r | m32rle | m68000 | m68k | m88k \ | ||||
| 	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | ||||
| 	| ip2k \ | ||||
| 	| m32r | m68000 | m68k | m88k | mcore \ | ||||
| 	| mips | mipsbe | mipseb | mipsel | mipsle \ | ||||
| 	| mips16 \ | ||||
| 	| mips64 | mips64el \ | ||||
| 	| mips64octeon | mips64octeonel \ | ||||
| 	| mips64orion | mips64orionel \ | ||||
| 	| mips64r5900 | mips64r5900el \ | ||||
| 	| mips64vr | mips64vrel \ | ||||
| 	| mips64orion | mips64orionel \ | ||||
| 	| mips64vr4100 | mips64vr4100el \ | ||||
| 	| mips64vr4300 | mips64vr4300el \ | ||||
| 	| mips64vr5000 | mips64vr5000el \ | ||||
| 	| mips64vr5900 | mips64vr5900el \ | ||||
| 	| mipsisa32 | mipsisa32el \ | ||||
| 	| mipsisa32r2 | mipsisa32r2el \ | ||||
| 	| mipsisa64 | mipsisa64el \ | ||||
| 	| mipsisa64r2 | mipsisa64r2el \ | ||||
| 	| mipsisa64sb1 | mipsisa64sb1el \ | ||||
| 	| mipsisa64sr71k | mipsisa64sr71kel \ | ||||
| 	| mipsr5900 | mipsr5900el \ | ||||
| 	| mipstx39 | mipstx39el \ | ||||
| 	| mn10200 | mn10300 \ | ||||
| 	| moxie \ | ||||
| 	| mt \ | ||||
| 	| msp430 \ | ||||
| 	| nds32 | nds32le | nds32be \ | ||||
| 	| nios | nios2 | nios2eb | nios2el \ | ||||
| 	| ns16k | ns32k \ | ||||
| 	| open8 \ | ||||
| 	| or1k | or32 \ | ||||
| 	| openrisc | or32 \ | ||||
| 	| pdp10 | pdp11 | pj | pjl \ | ||||
| 	| powerpc | powerpc64 | powerpc64le | powerpcle \ | ||||
| 	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | ||||
| 	| pyramid \ | ||||
| 	| rl78 | rx \ | ||||
| 	| score \ | ||||
| 	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | ||||
| 	| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | ||||
| 	| sh64 | sh64le \ | ||||
| 	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | ||||
| 	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | ||||
| 	| spu \ | ||||
| 	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ||||
| 	| ubicom32 \ | ||||
| 	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | ||||
| 	| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | ||||
| 	| strongarm \ | ||||
| 	| tahoe | thumb | tic4x | tic80 | tron \ | ||||
| 	| v850 | v850e \ | ||||
| 	| we32k \ | ||||
| 	| x86 | xc16x | xstormy16 | xtensa \ | ||||
| 	| z8k | z80) | ||||
| 	| x86 | xscale | xstormy16 | xtensa \ | ||||
| 	| z8k) | ||||
| 		basic_machine=$basic_machine-unknown | ||||
| 		;; | ||||
| 	c54x) | ||||
| 		basic_machine=tic54x-unknown | ||||
| 		;; | ||||
| 	c55x) | ||||
| 		basic_machine=tic55x-unknown | ||||
| 		;; | ||||
| 	c6x) | ||||
| 		basic_machine=tic6x-unknown | ||||
| 		;; | ||||
| 	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) | ||||
| 	m6811 | m68hc11 | m6812 | m68hc12) | ||||
| 		# Motorola 68HC11/12. | ||||
| 		basic_machine=$basic_machine-unknown | ||||
| 		os=-none | ||||
| 		;; | ||||
| 	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) | ||||
| 		;; | ||||
| 	ms1) | ||||
| 		basic_machine=mt-unknown | ||||
| 		;; | ||||
|  | ||||
| 	strongarm | thumb | xscale) | ||||
| 		basic_machine=arm-unknown | ||||
| 		;; | ||||
| 	xgate) | ||||
| 		basic_machine=$basic_machine-unknown | ||||
| 		os=-none | ||||
| 		;; | ||||
| 	xscaleeb) | ||||
| 		basic_machine=armeb-unknown | ||||
| 		;; | ||||
|  | ||||
| 	xscaleel) | ||||
| 		basic_machine=armel-unknown | ||||
| 		;; | ||||
|  | ||||
| 	# We use `pc' rather than `unknown' | ||||
| 	# because (1) that's what they normally are, and | ||||
| @@ -364,83 +290,58 @@ case $basic_machine in | ||||
| 	# Recognize the basic CPU types with company name. | ||||
| 	580-* \ | ||||
| 	| a29k-* \ | ||||
| 	| aarch64-* | aarch64_be-* \ | ||||
| 	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | ||||
| 	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | ||||
| 	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | ||||
| 	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | ||||
| 	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \ | ||||
| 	| avr-* | avr32-* \ | ||||
| 	| be32-* | be64-* \ | ||||
| 	| bfin-* | bs2000-* \ | ||||
| 	| c[123]* | c30-* | [cjt]90-* | c4x-* \ | ||||
| 	| c8051-* | clipper-* | craynv-* | cydra-* \ | ||||
| 	| avr-* \ | ||||
| 	| bs2000-* \ | ||||
| 	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | ||||
| 	| clipper-* | cydra-* \ | ||||
| 	| d10v-* | d30v-* | dlx-* \ | ||||
| 	| elxsi-* \ | ||||
| 	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | ||||
| 	| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | ||||
| 	| h8300-* | h8500-* \ | ||||
| 	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | ||||
| 	| hexagon-* \ | ||||
| 	| i*86-* | i860-* | i960-* | ia64-* \ | ||||
| 	| ip2k-* | iq2000-* \ | ||||
| 	| k1om-* \ | ||||
| 	| le32-* | le64-* \ | ||||
| 	| lm32-* \ | ||||
| 	| m32c-* | m32r-* | m32rle-* \ | ||||
| 	| ip2k-* \ | ||||
| 	| m32r-* \ | ||||
| 	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | ||||
| 	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | ||||
| 	| microblaze-* | microblazeel-* \ | ||||
| 	| m88110-* | m88k-* | mcore-* \ | ||||
| 	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | ||||
| 	| mips16-* \ | ||||
| 	| mips64-* | mips64el-* \ | ||||
| 	| mips64octeon-* | mips64octeonel-* \ | ||||
| 	| mips64orion-* | mips64orionel-* \ | ||||
| 	| mips64r5900-* | mips64r5900el-* \ | ||||
| 	| mips64vr-* | mips64vrel-* \ | ||||
| 	| mips64orion-* | mips64orionel-* \ | ||||
| 	| mips64vr4100-* | mips64vr4100el-* \ | ||||
| 	| mips64vr4300-* | mips64vr4300el-* \ | ||||
| 	| mips64vr5000-* | mips64vr5000el-* \ | ||||
| 	| mips64vr5900-* | mips64vr5900el-* \ | ||||
| 	| mipsisa32-* | mipsisa32el-* \ | ||||
| 	| mipsisa32r2-* | mipsisa32r2el-* \ | ||||
| 	| mipsisa64-* | mipsisa64el-* \ | ||||
| 	| mipsisa64r2-* | mipsisa64r2el-* \ | ||||
| 	| mipsisa64sb1-* | mipsisa64sb1el-* \ | ||||
| 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \ | ||||
| 	| mipsr5900-* | mipsr5900el-* \ | ||||
| 	| mipstx39-* | mipstx39el-* \ | ||||
| 	| mmix-* \ | ||||
| 	| mt-* \ | ||||
| 	| msp430-* \ | ||||
| 	| nds32-* | nds32le-* | nds32be-* \ | ||||
| 	| nios-* | nios2-* | nios2eb-* | nios2el-* \ | ||||
| 	| none-* | np1-* | ns16k-* | ns32k-* \ | ||||
| 	| open8-* \ | ||||
| 	| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | ||||
| 	| orion-* \ | ||||
| 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | ||||
| 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | ||||
| 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | ||||
| 	| pyramid-* \ | ||||
| 	| rl78-* | romp-* | rs6000-* | rx-* \ | ||||
| 	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | ||||
| 	| romp-* | rs6000-* \ | ||||
| 	| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | ||||
| 	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | ||||
| 	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | ||||
| 	| sparclite-* \ | ||||
| 	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | ||||
| 	| tahoe-* \ | ||||
| 	| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | ||||
| 	| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | ||||
| 	| tahoe-* | thumb-* \ | ||||
| 	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | ||||
| 	| tile*-* \ | ||||
| 	| tron-* \ | ||||
| 	| ubicom32-* \ | ||||
| 	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | ||||
| 	| vax-* \ | ||||
| 	| v850-* | v850e-* | vax-* \ | ||||
| 	| we32k-* \ | ||||
| 	| x86-* | x86_64-* | xc16x-* | xps100-* \ | ||||
| 	| xstormy16-* | xtensa*-* \ | ||||
| 	| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | ||||
| 	| xtensa-* \ | ||||
| 	| ymp-* \ | ||||
| 	| z8k-* | z80-*) | ||||
| 		;; | ||||
| 	# Recognize the basic CPU types without company name, with glob match. | ||||
| 	xtensa*) | ||||
| 		basic_machine=$basic_machine-unknown | ||||
| 	| z8k-*) | ||||
| 		;; | ||||
| 	# Recognize the various machine names and aliases which stand | ||||
| 	# for a CPU type and a company and sometimes even an OS. | ||||
| @@ -458,9 +359,6 @@ case $basic_machine in | ||||
| 		basic_machine=a29k-amd | ||||
| 		os=-udi | ||||
| 		;; | ||||
| 	abacus) | ||||
| 		basic_machine=abacus-unknown | ||||
| 		;; | ||||
| 	adobe68k) | ||||
| 		basic_machine=m68010-adobe | ||||
| 		os=-scout | ||||
| @@ -478,9 +376,6 @@ case $basic_machine in | ||||
| 	amd64) | ||||
| 		basic_machine=x86_64-pc | ||||
| 		;; | ||||
| 	amd64-*) | ||||
| 		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	amdahl) | ||||
| 		basic_machine=580-amdahl | ||||
| 		os=-sysv | ||||
| @@ -504,10 +399,6 @@ case $basic_machine in | ||||
| 		basic_machine=m68k-apollo | ||||
| 		os=-bsd | ||||
| 		;; | ||||
| 	aros) | ||||
| 		basic_machine=i386-pc | ||||
| 		os=-aros | ||||
| 		;; | ||||
| 	aux) | ||||
| 		basic_machine=m68k-apple | ||||
| 		os=-aux | ||||
| @@ -516,35 +407,10 @@ case $basic_machine in | ||||
| 		basic_machine=ns32k-sequent | ||||
| 		os=-dynix | ||||
| 		;; | ||||
| 	blackfin) | ||||
| 		basic_machine=bfin-unknown | ||||
| 		os=-linux | ||||
| 		;; | ||||
| 	blackfin-*) | ||||
| 		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		os=-linux | ||||
| 		;; | ||||
| 	bluegene*) | ||||
| 		basic_machine=powerpc-ibm | ||||
| 		os=-cnk | ||||
| 		;; | ||||
| 	c54x-*) | ||||
| 		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	c55x-*) | ||||
| 		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	c6x-*) | ||||
| 		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	c90) | ||||
| 		basic_machine=c90-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	cegcc) | ||||
| 		basic_machine=arm-unknown | ||||
| 		os=-cegcc | ||||
| 		;; | ||||
| 	convex-c1) | ||||
| 		basic_machine=c1-convex | ||||
| 		os=-bsd | ||||
| @@ -569,27 +435,12 @@ case $basic_machine in | ||||
| 		basic_machine=j90-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	craynv) | ||||
| 		basic_machine=craynv-cray | ||||
| 		os=-unicosmp | ||||
| 		;; | ||||
| 	cr16 | cr16-*) | ||||
| 		basic_machine=cr16-unknown | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	crds | unos) | ||||
| 		basic_machine=m68k-crds | ||||
| 		;; | ||||
| 	crisv32 | crisv32-* | etraxfs*) | ||||
| 		basic_machine=crisv32-axis | ||||
| 		;; | ||||
| 	cris | cris-* | etrax*) | ||||
| 		basic_machine=cris-axis | ||||
| 		;; | ||||
| 	crx) | ||||
| 		basic_machine=crx-unknown | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	da30 | da30-*) | ||||
| 		basic_machine=m68k-da30 | ||||
| 		;; | ||||
| @@ -612,14 +463,6 @@ case $basic_machine in | ||||
| 		basic_machine=m88k-motorola | ||||
| 		os=-sysv3 | ||||
| 		;; | ||||
| 	dicos) | ||||
| 		basic_machine=i686-pc | ||||
| 		os=-dicos | ||||
| 		;; | ||||
| 	djgpp) | ||||
| 		basic_machine=i586-pc | ||||
| 		os=-msdosdjgpp | ||||
| 		;; | ||||
| 	dpx20 | dpx20-*) | ||||
| 		basic_machine=rs6000-bull | ||||
| 		os=-bosx | ||||
| @@ -731,6 +574,7 @@ case $basic_machine in | ||||
| 	i370-ibm* | ibm*) | ||||
| 		basic_machine=i370-ibm | ||||
| 		;; | ||||
| # I'm not sure what "Sysv32" means.  Should this be sysv3.2? | ||||
| 	i*86v32) | ||||
| 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` | ||||
| 		os=-sysv32 | ||||
| @@ -769,14 +613,6 @@ case $basic_machine in | ||||
| 		basic_machine=m68k-isi | ||||
| 		os=-sysv | ||||
| 		;; | ||||
| 	m68knommu) | ||||
| 		basic_machine=m68k-unknown | ||||
| 		os=-linux | ||||
| 		;; | ||||
| 	m68knommu-*) | ||||
| 		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		os=-linux | ||||
| 		;; | ||||
| 	m88k-omron*) | ||||
| 		basic_machine=m88k-omron | ||||
| 		;; | ||||
| @@ -788,21 +624,10 @@ case $basic_machine in | ||||
| 		basic_machine=ns32k-utek | ||||
| 		os=-sysv | ||||
| 		;; | ||||
| 	microblaze*) | ||||
| 		basic_machine=microblaze-xilinx | ||||
| 		;; | ||||
| 	mingw64) | ||||
| 		basic_machine=x86_64-pc | ||||
| 		os=-mingw64 | ||||
| 		;; | ||||
| 	mingw32) | ||||
| 		basic_machine=i686-pc | ||||
| 		basic_machine=i386-pc | ||||
| 		os=-mingw32 | ||||
| 		;; | ||||
| 	mingw32ce) | ||||
| 		basic_machine=arm-unknown | ||||
| 		os=-mingw32ce | ||||
| 		;; | ||||
| 	miniframe) | ||||
| 		basic_machine=m68000-convergent | ||||
| 		;; | ||||
| @@ -816,6 +641,10 @@ case $basic_machine in | ||||
| 	mips3*) | ||||
| 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown | ||||
| 		;; | ||||
| 	mmix*) | ||||
| 		basic_machine=mmix-knuth | ||||
| 		os=-mmixware | ||||
| 		;; | ||||
| 	monitor) | ||||
| 		basic_machine=m68k-rom68k | ||||
| 		os=-coff | ||||
| @@ -828,21 +657,10 @@ case $basic_machine in | ||||
| 		basic_machine=i386-pc | ||||
| 		os=-msdos | ||||
| 		;; | ||||
| 	ms1-*) | ||||
| 		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` | ||||
| 		;; | ||||
| 	msys) | ||||
| 		basic_machine=i686-pc | ||||
| 		os=-msys | ||||
| 		;; | ||||
| 	mvs) | ||||
| 		basic_machine=i370-ibm | ||||
| 		os=-mvs | ||||
| 		;; | ||||
| 	nacl) | ||||
| 		basic_machine=le32-unknown | ||||
| 		os=-nacl | ||||
| 		;; | ||||
| 	ncr3000) | ||||
| 		basic_machine=i486-ncr | ||||
| 		os=-sysv4 | ||||
| @@ -907,11 +725,9 @@ case $basic_machine in | ||||
| 	np1) | ||||
| 		basic_machine=np1-gould | ||||
| 		;; | ||||
| 	neo-tandem) | ||||
| 		basic_machine=neo-tandem | ||||
| 		;; | ||||
| 	nse-tandem) | ||||
| 		basic_machine=nse-tandem | ||||
| 	nv1) | ||||
| 		basic_machine=nv1-cray | ||||
| 		os=-unicosmp | ||||
| 		;; | ||||
| 	nsr-tandem) | ||||
| 		basic_machine=nsr-tandem | ||||
| @@ -920,12 +736,9 @@ case $basic_machine in | ||||
| 		basic_machine=hppa1.1-oki | ||||
| 		os=-proelf | ||||
| 		;; | ||||
| 	openrisc | openrisc-*) | ||||
| 	or32 | or32-*) | ||||
| 		basic_machine=or32-unknown | ||||
| 		;; | ||||
| 	os400) | ||||
| 		basic_machine=powerpc-ibm | ||||
| 		os=-os400 | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	OSE68000 | ose68000) | ||||
| 		basic_machine=m68000-ericsson | ||||
| @@ -943,14 +756,6 @@ case $basic_machine in | ||||
| 		basic_machine=i860-intel | ||||
| 		os=-osf | ||||
| 		;; | ||||
| 	parisc) | ||||
| 		basic_machine=hppa-unknown | ||||
| 		os=-linux | ||||
| 		;; | ||||
| 	parisc-*) | ||||
| 		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		os=-linux | ||||
| 		;; | ||||
| 	pbd) | ||||
| 		basic_machine=sparc-tti | ||||
| 		;; | ||||
| @@ -960,12 +765,6 @@ case $basic_machine in | ||||
| 	pc532 | pc532-*) | ||||
| 		basic_machine=ns32k-pc532 | ||||
| 		;; | ||||
| 	pc98) | ||||
| 		basic_machine=i386-pc | ||||
| 		;; | ||||
| 	pc98-*) | ||||
| 		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	pentium | p5 | k5 | k6 | nexgen | viac3) | ||||
| 		basic_machine=i586-pc | ||||
| 		;; | ||||
| @@ -995,10 +794,9 @@ case $basic_machine in | ||||
| 		;; | ||||
| 	power)	basic_machine=power-ibm | ||||
| 		;; | ||||
| 	ppc | ppcbe)	basic_machine=powerpc-unknown | ||||
| 	ppc)	basic_machine=powerpc-unknown | ||||
| 		;; | ||||
| 	ppc-* | ppcbe-*) | ||||
| 		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	ppcle | powerpclittle | ppc-le | powerpc-little) | ||||
| 		basic_machine=powerpcle-unknown | ||||
| @@ -1023,14 +821,6 @@ case $basic_machine in | ||||
| 		basic_machine=i586-unknown | ||||
| 		os=-pw32 | ||||
| 		;; | ||||
| 	rdos | rdos64) | ||||
| 		basic_machine=x86_64-pc | ||||
| 		os=-rdos | ||||
| 		;; | ||||
| 	rdos32) | ||||
| 		basic_machine=i386-pc | ||||
| 		os=-rdos | ||||
| 		;; | ||||
| 	rom68k) | ||||
| 		basic_machine=m68k-rom68k | ||||
| 		os=-coff | ||||
| @@ -1057,10 +847,6 @@ case $basic_machine in | ||||
| 	sb1el) | ||||
| 		basic_machine=mipsisa64sb1el-unknown | ||||
| 		;; | ||||
| 	sde) | ||||
| 		basic_machine=mipsisa32-sde | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	sei) | ||||
| 		basic_machine=mips-sei | ||||
| 		os=-seiux | ||||
| @@ -1072,9 +858,6 @@ case $basic_machine in | ||||
| 		basic_machine=sh-hitachi | ||||
| 		os=-hms | ||||
| 		;; | ||||
| 	sh5el) | ||||
| 		basic_machine=sh5le-unknown | ||||
| 		;; | ||||
| 	sh64) | ||||
| 		basic_machine=sh64-unknown | ||||
| 		;; | ||||
| @@ -1096,9 +879,6 @@ case $basic_machine in | ||||
| 		basic_machine=i860-stratus | ||||
| 		os=-sysv4 | ||||
| 		;; | ||||
| 	strongarm-* | thumb-*) | ||||
| 		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` | ||||
| 		;; | ||||
| 	sun2) | ||||
| 		basic_machine=m68000-sun | ||||
| 		;; | ||||
| @@ -1155,9 +935,17 @@ case $basic_machine in | ||||
| 		basic_machine=t90-cray | ||||
| 		os=-unicos | ||||
| 		;; | ||||
| 	tile*) | ||||
| 		basic_machine=$basic_machine-unknown | ||||
| 		os=-linux-gnu | ||||
| 	tic54x | c54x*) | ||||
| 		basic_machine=tic54x-unknown | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	tic55x | c55x*) | ||||
| 		basic_machine=tic55x-unknown | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	tic6x | c6x*) | ||||
| 		basic_machine=tic6x-unknown | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	tx39) | ||||
| 		basic_machine=mipstx39-unknown | ||||
| @@ -1172,10 +960,6 @@ case $basic_machine in | ||||
| 	tower | tower-32) | ||||
| 		basic_machine=m68k-ncr | ||||
| 		;; | ||||
| 	tpf) | ||||
| 		basic_machine=s390x-ibm | ||||
| 		os=-tpf | ||||
| 		;; | ||||
| 	udi29k) | ||||
| 		basic_machine=a29k-amd | ||||
| 		os=-udi | ||||
| @@ -1219,16 +1003,9 @@ case $basic_machine in | ||||
| 		basic_machine=hppa1.1-winbond | ||||
| 		os=-proelf | ||||
| 		;; | ||||
| 	xbox) | ||||
| 		basic_machine=i686-pc | ||||
| 		os=-mingw32 | ||||
| 		;; | ||||
| 	xps | xps100) | ||||
| 		basic_machine=xps100-honeywell | ||||
| 		;; | ||||
| 	xscale-* | xscalee[bl]-*) | ||||
| 		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` | ||||
| 		;; | ||||
| 	ymp) | ||||
| 		basic_machine=ymp-cray | ||||
| 		os=-unicos | ||||
| @@ -1237,10 +1014,6 @@ case $basic_machine in | ||||
| 		basic_machine=z8k-unknown | ||||
| 		os=-sim | ||||
| 		;; | ||||
| 	z80-*-coff) | ||||
| 		basic_machine=z80-unknown | ||||
| 		os=-sim | ||||
| 		;; | ||||
| 	none) | ||||
| 		basic_machine=none-none | ||||
| 		os=-none | ||||
| @@ -1260,9 +1033,6 @@ case $basic_machine in | ||||
| 	romp) | ||||
| 		basic_machine=romp-ibm | ||||
| 		;; | ||||
| 	mmix) | ||||
| 		basic_machine=mmix-knuth | ||||
| 		;; | ||||
| 	rs6000) | ||||
| 		basic_machine=rs6000-ibm | ||||
| 		;; | ||||
| @@ -1279,10 +1049,13 @@ case $basic_machine in | ||||
| 	we32k) | ||||
| 		basic_machine=we32k-att | ||||
| 		;; | ||||
| 	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) | ||||
| 	sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) | ||||
| 		basic_machine=sh-unknown | ||||
| 		;; | ||||
| 	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) | ||||
| 	sh64) | ||||
| 		basic_machine=sh64-unknown | ||||
| 		;; | ||||
| 	sparc | sparcv9 | sparcv9b) | ||||
| 		basic_machine=sparc-sun | ||||
| 		;; | ||||
| 	cydra) | ||||
| @@ -1326,12 +1099,9 @@ esac | ||||
| if [ x"$os" != x"" ] | ||||
| then | ||||
| case $os in | ||||
| 	# First match some system type aliases | ||||
| 	# that might get confused with valid system types. | ||||
|         # First match some system type aliases | ||||
|         # that might get confused with valid system types. | ||||
| 	# -solaris* is a basic system type, with this one exception. | ||||
| 	-auroraux) | ||||
| 		os=-auroraux | ||||
| 		;; | ||||
| 	-solaris1 | -solaris1.*) | ||||
| 		os=`echo $os | sed -e 's|solaris1|sunos4|'` | ||||
| 		;; | ||||
| @@ -1352,31 +1122,25 @@ case $os in | ||||
| 	# Each alternative MUST END IN A *, to match a version number. | ||||
| 	# -sysv* is not here because it comes later, after sysvr4. | ||||
| 	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | ||||
| 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | ||||
| 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | ||||
| 	      | -sym* | -kopensolaris* | -plan9* \ | ||||
| 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | ||||
| 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | ||||
| 	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | ||||
| 	      | -aos* | -aros* \ | ||||
| 	      | -aos* \ | ||||
| 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | ||||
| 	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | ||||
| 	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | ||||
| 	      | -bitrig* | -openbsd* | -solidbsd* \ | ||||
| 	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | ||||
| 	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | ||||
| 	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | ||||
| 	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | ||||
| 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | ||||
| 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | ||||
| 	      | -chorusos* | -chorusrdb* | -cegcc* \ | ||||
| 	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | ||||
| 	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | ||||
| 	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | ||||
| 	      | -uxpv* | -beos* | -mpeix* | -udk* \ | ||||
| 	      | -chorusos* | -chorusrdb* \ | ||||
| 	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | ||||
| 	      | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | ||||
| 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | ||||
| 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | ||||
| 	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | ||||
| 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | ||||
| 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | ||||
| 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | ||||
| 	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) | ||||
| 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) | ||||
| 	# Remember, each alternative MUST END IN *, to match a version number. | ||||
| 		;; | ||||
| 	-qnx*) | ||||
| @@ -1394,15 +1158,12 @@ case $os in | ||||
| 		os=`echo $os | sed -e 's|nto|nto-qnx|'` | ||||
| 		;; | ||||
| 	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | ||||
| 	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | ||||
| 	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | ||||
| 	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) | ||||
| 		;; | ||||
| 	-mac*) | ||||
| 		os=`echo $os | sed -e 's|mac|macos|'` | ||||
| 		;; | ||||
| 	-linux-dietlibc) | ||||
| 		os=-linux-dietlibc | ||||
| 		;; | ||||
| 	-linux*) | ||||
| 		os=`echo $os | sed -e 's|linux|linux-gnu|'` | ||||
| 		;; | ||||
| @@ -1415,9 +1176,6 @@ case $os in | ||||
| 	-opened*) | ||||
| 		os=-openedition | ||||
| 		;; | ||||
| 	-os400*) | ||||
| 		os=-os400 | ||||
| 		;; | ||||
| 	-wince*) | ||||
| 		os=-wince | ||||
| 		;; | ||||
| @@ -1439,9 +1197,6 @@ case $os in | ||||
| 	-atheos*) | ||||
| 		os=-atheos | ||||
| 		;; | ||||
| 	-syllable*) | ||||
| 		os=-syllable | ||||
| 		;; | ||||
| 	-386bsd) | ||||
| 		os=-bsd | ||||
| 		;; | ||||
| @@ -1464,9 +1219,6 @@ case $os in | ||||
| 	-sinix*) | ||||
| 		os=-sysv4 | ||||
| 		;; | ||||
| 	-tpf*) | ||||
| 		os=-tpf | ||||
| 		;; | ||||
| 	-triton*) | ||||
| 		os=-sysv3 | ||||
| 		;; | ||||
| @@ -1500,13 +1252,8 @@ case $os in | ||||
| 	-aros*) | ||||
| 		os=-aros | ||||
| 		;; | ||||
| 	-zvmoe) | ||||
| 		os=-zvmoe | ||||
| 		;; | ||||
| 	-dicos*) | ||||
| 		os=-dicos | ||||
| 		;; | ||||
| 	-nacl*) | ||||
| 	-kaos*) | ||||
| 		os=-kaos | ||||
| 		;; | ||||
| 	-none) | ||||
| 		;; | ||||
| @@ -1530,12 +1277,6 @@ else | ||||
| # system, and we'll never get to this point. | ||||
|  | ||||
| case $basic_machine in | ||||
| 	score-*) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	spu-*) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	*-acorn) | ||||
| 		os=-riscix1.2 | ||||
| 		;; | ||||
| @@ -1545,24 +1286,9 @@ case $basic_machine in | ||||
| 	arm*-semi) | ||||
| 		os=-aout | ||||
| 		;; | ||||
| 	c4x-* | tic4x-*) | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	c8051-*) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	hexagon-*) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	tic54x-*) | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	tic55x-*) | ||||
| 		os=-coff | ||||
| 		;; | ||||
| 	tic6x-*) | ||||
| 		os=-coff | ||||
| 		;; | ||||
|     c4x-* | tic4x-*) | ||||
|         os=-coff | ||||
|         ;; | ||||
| 	# This must come before the *-dec entry. | ||||
| 	pdp10-*) | ||||
| 		os=-tops20 | ||||
| @@ -1581,22 +1307,19 @@ case $basic_machine in | ||||
| 		;; | ||||
| 	m68000-sun) | ||||
| 		os=-sunos3 | ||||
| 		# This also exists in the configure program, but was not the | ||||
| 		# default. | ||||
| 		# os=-sunos4 | ||||
| 		;; | ||||
| 	m68*-cisco) | ||||
| 		os=-aout | ||||
| 		;; | ||||
| 	mep-*) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	mips*-cisco) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	mips*-*) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	or1k-*) | ||||
| 		os=-elf | ||||
| 		;; | ||||
| 	or32-*) | ||||
| 		os=-coff | ||||
| 		;; | ||||
| @@ -1609,15 +1332,9 @@ case $basic_machine in | ||||
| 	*-be) | ||||
| 		os=-beos | ||||
| 		;; | ||||
| 	*-haiku) | ||||
| 		os=-haiku | ||||
| 		;; | ||||
| 	*-ibm) | ||||
| 		os=-aix | ||||
| 		;; | ||||
| 	*-knuth) | ||||
| 		os=-mmixware | ||||
| 		;; | ||||
| 	*-wec) | ||||
| 		os=-proelf | ||||
| 		;; | ||||
| @@ -1720,7 +1437,7 @@ case $basic_machine in | ||||
| 			-sunos*) | ||||
| 				vendor=sun | ||||
| 				;; | ||||
| 			-cnk*|-aix*) | ||||
| 			-aix*) | ||||
| 				vendor=ibm | ||||
| 				;; | ||||
| 			-beos*) | ||||
| @@ -1750,15 +1467,9 @@ case $basic_machine in | ||||
| 			-mvs* | -opened*) | ||||
| 				vendor=ibm | ||||
| 				;; | ||||
| 			-os400*) | ||||
| 				vendor=ibm | ||||
| 				;; | ||||
| 			-ptx*) | ||||
| 				vendor=sequent | ||||
| 				;; | ||||
| 			-tpf*) | ||||
| 				vendor=ibm | ||||
| 				;; | ||||
| 			-vxsim* | -vxworks* | -windiss*) | ||||
| 				vendor=wrs | ||||
| 				;; | ||||
| @@ -1783,7 +1494,7 @@ case $basic_machine in | ||||
| esac | ||||
|  | ||||
| echo $basic_machine$os | ||||
| exit | ||||
| exit 0 | ||||
|  | ||||
| # Local variables: | ||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #!/bin/sh | ||||
| # install - install a program, script, or datafile | ||||
|  | ||||
| scriptversion=2006-10-14.15 | ||||
| scriptversion=2003-06-13.21 | ||||
|  | ||||
| # This originates from X11R5 (mit/util/scripts/install.sh), which was | ||||
| # later released in X11R6 (xc/config/util/install.sh) with the | ||||
| @@ -39,24 +39,15 @@ scriptversion=2006-10-14.15 | ||||
| # when there is no Makefile. | ||||
| # | ||||
| # This script is compatible with the BSD install script, but was written | ||||
| # from scratch. | ||||
|  | ||||
| nl=' | ||||
| ' | ||||
| IFS=" ""	$nl" | ||||
| # from scratch.  It can only install one file at a time, a restriction | ||||
| # shared with many OS's install programs. | ||||
|  | ||||
| # set DOITPROG to echo to test this script | ||||
|  | ||||
| # Don't use :- since 4.3BSD and earlier shells don't like it. | ||||
| doit="${DOITPROG-}" | ||||
| if test -z "$doit"; then | ||||
|   doit_exec=exec | ||||
| else | ||||
|   doit_exec=$doit | ||||
| fi | ||||
|  | ||||
| # Put in absolute file names if you don't have them in your path; | ||||
| # or use environment vars. | ||||
| # put in absolute paths if you don't have them in your path; or use env. vars. | ||||
|  | ||||
| mvprog="${MVPROG-mv}" | ||||
| cpprog="${CPPROG-cp}" | ||||
| @@ -67,13 +58,10 @@ stripprog="${STRIPPROG-strip}" | ||||
| rmprog="${RMPROG-rm}" | ||||
| mkdirprog="${MKDIRPROG-mkdir}" | ||||
|  | ||||
| posix_glob= | ||||
| posix_mkdir= | ||||
|  | ||||
| # Desired mode of installed file. | ||||
| mode=0755 | ||||
|  | ||||
| chmodcmd=$chmodprog | ||||
| transformbasename= | ||||
| transform_arg= | ||||
| instcmd="$mvprog" | ||||
| chmodcmd="$chmodprog 0755" | ||||
| chowncmd= | ||||
| chgrpcmd= | ||||
| stripcmd= | ||||
| @@ -82,27 +70,22 @@ mvcmd="$mvprog" | ||||
| src= | ||||
| dst= | ||||
| dir_arg= | ||||
| dstarg= | ||||
| no_target_directory= | ||||
|  | ||||
| usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE | ||||
|    or: $0 [OPTION]... SRCFILES... DIRECTORY | ||||
|    or: $0 [OPTION]... -t DIRECTORY SRCFILES... | ||||
|    or: $0 [OPTION]... -d DIRECTORIES... | ||||
| usage="Usage: $0 [OPTION]... SRCFILE DSTFILE | ||||
|    or: $0 -d DIR1 DIR2... | ||||
|  | ||||
| In the 1st form, copy SRCFILE to DSTFILE. | ||||
| In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. | ||||
| In the 4th, create DIRECTORIES. | ||||
| In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default. | ||||
| In the second, create the directory path DIR. | ||||
|  | ||||
| Options: | ||||
| -c         (ignored) | ||||
| -b=TRANSFORMBASENAME | ||||
| -c         copy source (using $cpprog) instead of moving (using $mvprog). | ||||
| -d         create directories instead of installing files. | ||||
| -g GROUP   $chgrpprog installed files to GROUP. | ||||
| -m MODE    $chmodprog installed files to MODE. | ||||
| -o USER    $chownprog installed files to USER. | ||||
| -s         $stripprog installed files. | ||||
| -t DIRECTORY  install into DIRECTORY. | ||||
| -T         report an error if DSTFILE is a directory. | ||||
| -g GROUP   $chgrp installed files to GROUP. | ||||
| -m MODE    $chmod installed files to MODE. | ||||
| -o USER    $chown installed files to USER. | ||||
| -s         strip installed files (using $stripprog). | ||||
| -t=TRANSFORM | ||||
| --help     display this help and exit. | ||||
| --version  display version info and exit. | ||||
|  | ||||
| @@ -110,9 +93,14 @@ Environment variables override the default commands: | ||||
|   CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG | ||||
| " | ||||
|  | ||||
| while test $# -ne 0; do | ||||
| while test -n "$1"; do | ||||
|   case $1 in | ||||
|     -c) shift | ||||
|     -b=*) transformbasename=`echo $1 | sed 's/-b=//'` | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -c) instcmd=$cpprog | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -d) dir_arg=true | ||||
| @@ -124,17 +112,11 @@ while test $# -ne 0; do | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     --help) echo "$usage"; exit $?;; | ||||
|     --help) echo "$usage"; exit 0;; | ||||
|  | ||||
|     -m) mode=$2 | ||||
|     -m) chmodcmd="$chmodprog $2" | ||||
|         shift | ||||
|         shift | ||||
| 	case $mode in | ||||
| 	  *' '* | *'	'* | *' | ||||
| '*	  | *'*'* | *'?'* | *'['*) | ||||
| 	    echo "$0: invalid mode: $mode" >&2 | ||||
| 	    exit 1;; | ||||
| 	esac | ||||
|         continue;; | ||||
|  | ||||
|     -o) chowncmd="$chownprog $2" | ||||
| @@ -146,358 +128,155 @@ while test $# -ne 0; do | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -t) dstarg=$2 | ||||
| 	shift | ||||
| 	shift | ||||
| 	continue;; | ||||
|     -t=*) transformarg=`echo $1 | sed 's/-t=//'` | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
|     -T) no_target_directory=true | ||||
| 	shift | ||||
| 	continue;; | ||||
|     --version) echo "$0 $scriptversion"; exit 0;; | ||||
|  | ||||
|     --version) echo "$0 $scriptversion"; exit $?;; | ||||
|  | ||||
|     --)	shift | ||||
| 	break;; | ||||
|  | ||||
|     -*)	echo "$0: invalid option: $1" >&2 | ||||
| 	exit 1;; | ||||
|  | ||||
|     *)  break;; | ||||
|     *)  if test -z "$src"; then | ||||
|           src=$1 | ||||
|         else | ||||
|           # this colon is to work around a 386BSD /bin/sh bug | ||||
|           : | ||||
|           dst=$1 | ||||
|         fi | ||||
|         shift | ||||
|         continue;; | ||||
|   esac | ||||
| done | ||||
|  | ||||
| if test $# -ne 0 && test -z "$dir_arg$dstarg"; then | ||||
|   # When -d is used, all remaining arguments are directories to create. | ||||
|   # When -t is used, the destination is already specified. | ||||
|   # Otherwise, the last argument is the destination.  Remove it from $@. | ||||
|   for arg | ||||
|   do | ||||
|     if test -n "$dstarg"; then | ||||
|       # $@ is not empty: it contains at least $arg. | ||||
|       set fnord "$@" "$dstarg" | ||||
|       shift # fnord | ||||
|     fi | ||||
|     shift # arg | ||||
|     dstarg=$arg | ||||
| if test -z "$src"; then | ||||
|   echo "$0: no input file specified." >&2 | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| if test -n "$dir_arg"; then | ||||
|   dst=$src | ||||
|   src= | ||||
|  | ||||
|   if test -d "$dst"; then | ||||
|     instcmd=: | ||||
|     chmodcmd= | ||||
|   else | ||||
|     instcmd=$mkdirprog | ||||
|   fi | ||||
| else | ||||
|   # Waiting for this to be detected by the "$instcmd $src $dsttmp" command | ||||
|   # might cause directories to be created, which would be especially bad | ||||
|   # if $src (and thus $dsttmp) contains '*'. | ||||
|   if test ! -f "$src" && test ! -d "$src"; then | ||||
|     echo "$0: $src does not exist." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|  | ||||
|   if test -z "$dst"; then | ||||
|     echo "$0: no destination specified." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|  | ||||
|   # If destination is a directory, append the input filename; won't work | ||||
|   # if double slashes aren't ignored. | ||||
|   if test -d "$dst"; then | ||||
|     dst=$dst/`basename "$src"` | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| ## this sed command emulates the dirname command | ||||
| dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` | ||||
|  | ||||
| # Make sure that the destination directory exists. | ||||
| # (this part is taken from Noah Friedman's mkinstalldirs script.) | ||||
|  | ||||
| # Skip lots of stat calls in the usual case. | ||||
| if test ! -d "$dstdir"; then | ||||
|   defaultIFS=' | ||||
| 	' | ||||
|   IFS="${IFS-$defaultIFS}" | ||||
|  | ||||
|   oIFS=$IFS | ||||
|   # Some sh's can't handle IFS=/ for some reason. | ||||
|   IFS='%' | ||||
|   set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` | ||||
|   IFS=$oIFS | ||||
|  | ||||
|   pathcomp= | ||||
|  | ||||
|   while test $# -ne 0 ; do | ||||
|     pathcomp=$pathcomp$1 | ||||
|     shift | ||||
|     test -d "$pathcomp" || $mkdirprog "$pathcomp" | ||||
|     pathcomp=$pathcomp/ | ||||
|   done | ||||
| fi | ||||
|  | ||||
| if test $# -eq 0; then | ||||
|   if test -z "$dir_arg"; then | ||||
|     echo "$0: no input file specified." >&2 | ||||
|     exit 1 | ||||
|   fi | ||||
|   # It's OK to call `install-sh -d' without argument. | ||||
|   # This can happen when creating conditional directories. | ||||
|   exit 0 | ||||
| fi | ||||
| if test -n "$dir_arg"; then | ||||
|   $doit $instcmd "$dst" \ | ||||
|     && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ | ||||
|     && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ | ||||
|     && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ | ||||
|     && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } | ||||
|  | ||||
| if test -z "$dir_arg"; then | ||||
| else | ||||
|   # If we're going to rename the final executable, determine the name now. | ||||
|   if test -z "$transformarg"; then | ||||
|     dstfile=`basename "$dst"` | ||||
|   else | ||||
|     dstfile=`basename "$dst" $transformbasename \ | ||||
|              | sed $transformarg`$transformbasename | ||||
|   fi | ||||
|  | ||||
|   # don't allow the sed command to completely eliminate the filename. | ||||
|   test -z "$dstfile" && dstfile=`basename "$dst"` | ||||
|  | ||||
|   # Make a couple of temp file names in the proper directory. | ||||
|   dsttmp=$dstdir/_inst.$$_ | ||||
|   rmtmp=$dstdir/_rm.$$_ | ||||
|  | ||||
|   # Trap to clean up those temp files at exit. | ||||
|   trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 | ||||
|   trap '(exit $?); exit' 1 2 13 15 | ||||
|  | ||||
|   # Set umask so as not to create temps with too-generous modes. | ||||
|   # However, 'strip' requires both read and write access to temps. | ||||
|   case $mode in | ||||
|     # Optimize common cases. | ||||
|     *644) cp_umask=133;; | ||||
|     *755) cp_umask=22;; | ||||
|   # Move or copy the file name to the temp name | ||||
|   $doit $instcmd "$src" "$dsttmp" && | ||||
|  | ||||
|     *[0-7]) | ||||
|       if test -z "$stripcmd"; then | ||||
| 	u_plus_rw= | ||||
|       else | ||||
| 	u_plus_rw='% 200' | ||||
|       fi | ||||
|       cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; | ||||
|     *) | ||||
|       if test -z "$stripcmd"; then | ||||
| 	u_plus_rw= | ||||
|       else | ||||
| 	u_plus_rw=,u+rw | ||||
|       fi | ||||
|       cp_umask=$mode$u_plus_rw;; | ||||
|   esac | ||||
| fi | ||||
|   # and set any options; do chmod last to preserve setuid bits. | ||||
|   # | ||||
|   # If any of these fail, we abort the whole thing.  If we want to | ||||
|   # ignore errors from any of these, just make sure not to ignore | ||||
|   # errors from the above "$doit $instcmd $src $dsttmp" command. | ||||
|   # | ||||
|   { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ | ||||
|     && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ | ||||
|     && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ | ||||
|     && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && | ||||
|  | ||||
| for src | ||||
| do | ||||
|   # Protect names starting with `-'. | ||||
|   case $src in | ||||
|     -*) src=./$src ;; | ||||
|   esac | ||||
|  | ||||
|   if test -n "$dir_arg"; then | ||||
|     dst=$src | ||||
|     dstdir=$dst | ||||
|     test -d "$dstdir" | ||||
|     dstdir_status=$? | ||||
|   else | ||||
|  | ||||
|     # Waiting for this to be detected by the "$cpprog $src $dsttmp" command | ||||
|     # might cause directories to be created, which would be especially bad | ||||
|     # if $src (and thus $dsttmp) contains '*'. | ||||
|     if test ! -f "$src" && test ! -d "$src"; then | ||||
|       echo "$0: $src does not exist." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|  | ||||
|     if test -z "$dstarg"; then | ||||
|       echo "$0: no destination specified." >&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|  | ||||
|     dst=$dstarg | ||||
|     # Protect names starting with `-'. | ||||
|     case $dst in | ||||
|       -*) dst=./$dst ;; | ||||
|     esac | ||||
|  | ||||
|     # If destination is a directory, append the input filename; won't work | ||||
|     # if double slashes aren't ignored. | ||||
|     if test -d "$dst"; then | ||||
|       if test -n "$no_target_directory"; then | ||||
| 	echo "$0: $dstarg: Is a directory" >&2 | ||||
| 	exit 1 | ||||
|       fi | ||||
|       dstdir=$dst | ||||
|       dst=$dstdir/`basename "$src"` | ||||
|       dstdir_status=0 | ||||
|     else | ||||
|       # Prefer dirname, but fall back on a substitute if dirname fails. | ||||
|       dstdir=` | ||||
| 	(dirname "$dst") 2>/dev/null || | ||||
| 	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ | ||||
| 	     X"$dst" : 'X\(//\)[^/]' \| \ | ||||
| 	     X"$dst" : 'X\(//\)$' \| \ | ||||
| 	     X"$dst" : 'X\(/\)' \| . 2>/dev/null || | ||||
| 	echo X"$dst" | | ||||
| 	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\/\)[^/].*/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\/\)$/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 /^X\(\/\).*/{ | ||||
| 		   s//\1/ | ||||
| 		   q | ||||
| 		 } | ||||
| 		 s/.*/./; q' | ||||
|       ` | ||||
|  | ||||
|       test -d "$dstdir" | ||||
|       dstdir_status=$? | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   obsolete_mkdir_used=false | ||||
|  | ||||
|   if test $dstdir_status != 0; then | ||||
|     case $posix_mkdir in | ||||
|       '') | ||||
| 	# Create intermediate dirs using mode 755 as modified by the umask. | ||||
| 	# This is like FreeBSD 'install' as of 1997-10-28. | ||||
| 	umask=`umask` | ||||
| 	case $stripcmd.$umask in | ||||
| 	  # Optimize common cases. | ||||
| 	  *[2367][2367]) mkdir_umask=$umask;; | ||||
| 	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; | ||||
|  | ||||
| 	  *[0-7]) | ||||
| 	    mkdir_umask=`expr $umask + 22 \ | ||||
| 	      - $umask % 100 % 40 + $umask % 20 \ | ||||
| 	      - $umask % 10 % 4 + $umask % 2 | ||||
| 	    `;; | ||||
| 	  *) mkdir_umask=$umask,go-w;; | ||||
| 	esac | ||||
|  | ||||
| 	# With -d, create the new directory with the user-specified mode. | ||||
| 	# Otherwise, rely on $mkdir_umask. | ||||
| 	if test -n "$dir_arg"; then | ||||
| 	  mkdir_mode=-m$mode | ||||
| 	else | ||||
| 	  mkdir_mode= | ||||
| 	fi | ||||
|  | ||||
| 	posix_mkdir=false | ||||
| 	case $umask in | ||||
| 	  *[123567][0-7][0-7]) | ||||
| 	    # POSIX mkdir -p sets u+wx bits regardless of umask, which | ||||
| 	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0. | ||||
| 	    ;; | ||||
| 	  *) | ||||
| 	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ | ||||
| 	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 | ||||
|  | ||||
| 	    if (umask $mkdir_umask && | ||||
| 		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 | ||||
| 	    then | ||||
| 	      if test -z "$dir_arg" || { | ||||
| 		   # Check for POSIX incompatibilities with -m. | ||||
| 		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or | ||||
| 		   # other-writeable bit of parent directory when it shouldn't. | ||||
| 		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. | ||||
| 		   ls_ld_tmpdir=`ls -ld "$tmpdir"` | ||||
| 		   case $ls_ld_tmpdir in | ||||
| 		     d????-?r-*) different_mode=700;; | ||||
| 		     d????-?--*) different_mode=755;; | ||||
| 		     *) false;; | ||||
| 		   esac && | ||||
| 		   $mkdirprog -m$different_mode -p -- "$tmpdir" && { | ||||
| 		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"` | ||||
| 		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" | ||||
| 		   } | ||||
| 		 } | ||||
| 	      then posix_mkdir=: | ||||
| 	      fi | ||||
| 	      rmdir "$tmpdir/d" "$tmpdir" | ||||
| 	    else | ||||
| 	      # Remove any dirs left behind by ancient mkdir implementations. | ||||
| 	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null | ||||
| 	    fi | ||||
| 	    trap '' 0;; | ||||
| 	esac;; | ||||
|     esac | ||||
|  | ||||
|     if | ||||
|       $posix_mkdir && ( | ||||
| 	umask $mkdir_umask && | ||||
| 	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" | ||||
|       ) | ||||
|     then : | ||||
|     else | ||||
|  | ||||
|       # The umask is ridiculous, or mkdir does not conform to POSIX, | ||||
|       # or it failed possibly due to a race condition.  Create the | ||||
|       # directory the slow way, step by step, checking for races as we go. | ||||
|  | ||||
|       case $dstdir in | ||||
| 	/*) prefix=/ ;; | ||||
| 	-*) prefix=./ ;; | ||||
| 	*)  prefix= ;; | ||||
|       esac | ||||
|  | ||||
|       case $posix_glob in | ||||
|         '') | ||||
| 	  if (set -f) 2>/dev/null; then | ||||
| 	    posix_glob=true | ||||
| 	  else | ||||
| 	    posix_glob=false | ||||
| 	  fi ;; | ||||
|       esac | ||||
|  | ||||
|       oIFS=$IFS | ||||
|       IFS=/ | ||||
|       $posix_glob && set -f | ||||
|       set fnord $dstdir | ||||
|       shift | ||||
|       $posix_glob && set +f | ||||
|       IFS=$oIFS | ||||
|  | ||||
|       prefixes= | ||||
|  | ||||
|       for d | ||||
|       do | ||||
| 	test -z "$d" && continue | ||||
|  | ||||
| 	prefix=$prefix$d | ||||
| 	if test -d "$prefix"; then | ||||
| 	  prefixes= | ||||
| 	else | ||||
| 	  if $posix_mkdir; then | ||||
| 	    (umask=$mkdir_umask && | ||||
| 	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break | ||||
| 	    # Don't fail if two instances are running concurrently. | ||||
| 	    test -d "$prefix" || exit 1 | ||||
| 	  else | ||||
| 	    case $prefix in | ||||
| 	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; | ||||
| 	      *) qprefix=$prefix;; | ||||
| 	    esac | ||||
| 	    prefixes="$prefixes '$qprefix'" | ||||
| 	  fi | ||||
| 	fi | ||||
| 	prefix=$prefix/ | ||||
|       done | ||||
|  | ||||
|       if test -n "$prefixes"; then | ||||
| 	# Don't fail if two instances are running concurrently. | ||||
| 	(umask $mkdir_umask && | ||||
| 	 eval "\$doit_exec \$mkdirprog $prefixes") || | ||||
| 	  test -d "$dstdir" || exit 1 | ||||
| 	obsolete_mkdir_used=true | ||||
|       fi | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   if test -n "$dir_arg"; then | ||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && | ||||
|     { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && | ||||
|     { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || | ||||
|       test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 | ||||
|   else | ||||
|  | ||||
|     # Make a couple of temp file names in the proper directory. | ||||
|     dsttmp=$dstdir/_inst.$$_ | ||||
|     rmtmp=$dstdir/_rm.$$_ | ||||
|  | ||||
|     # Trap to clean up those temp files at exit. | ||||
|     trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 | ||||
|  | ||||
|     # Copy the file name to the temp name. | ||||
|     (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && | ||||
|  | ||||
|     # and set any options; do chmod last to preserve setuid bits. | ||||
|     # | ||||
|     # If any of these fail, we abort the whole thing.  If we want to | ||||
|     # ignore errors from any of these, just make sure not to ignore | ||||
|     # errors from the above "$doit $cpprog $src $dsttmp" command. | ||||
|     # | ||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ | ||||
|       && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ | ||||
|       && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ | ||||
|       && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && | ||||
|  | ||||
|     # Now rename the file to the real destination. | ||||
|     { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ | ||||
|   # Now remove or move aside any old file at destination location.  We | ||||
|   # try this two ways since rm can't unlink itself on some systems and | ||||
|   # the destination file might be busy for other reasons.  In this case, | ||||
|   # the final cleanup might fail but the new file should still install | ||||
|   # successfully. | ||||
|   { | ||||
|     if test -f "$dstdir/$dstfile"; then | ||||
|       $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ | ||||
|       || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ | ||||
|       || { | ||||
| 	   # The rename failed, perhaps because mv can't rename something else | ||||
| 	   # to itself, or perhaps because mv is so ancient that it does not | ||||
| 	   # support -f. | ||||
| 	  echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 | ||||
| 	  (exit 1); exit | ||||
|       } | ||||
|     else | ||||
|       : | ||||
|     fi | ||||
|   } && | ||||
|  | ||||
| 	   # Now remove or move aside any old file at destination location. | ||||
| 	   # We try this two ways since rm can't unlink itself on some | ||||
| 	   # systems and the destination file might be busy for other | ||||
| 	   # reasons.  In this case, the final cleanup might fail but the new | ||||
| 	   # file should still install successfully. | ||||
| 	   { | ||||
| 	     if test -f "$dst"; then | ||||
| 	       $doit $rmcmd -f "$dst" 2>/dev/null \ | ||||
| 	       || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ | ||||
| 		     && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ | ||||
| 	       || { | ||||
| 		 echo "$0: cannot unlink or rename $dst" >&2 | ||||
| 		 (exit 1); exit 1 | ||||
| 	       } | ||||
| 	     else | ||||
| 	       : | ||||
| 	     fi | ||||
| 	   } && | ||||
|   # Now rename the file to the real destination. | ||||
|   $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" | ||||
| fi && | ||||
|  | ||||
| 	   # Now rename the file to the real destination. | ||||
| 	   $doit $mvcmd "$dsttmp" "$dst" | ||||
| 	 } | ||||
|     } || exit 1 | ||||
|  | ||||
|     trap '' 0 | ||||
|   fi | ||||
| done | ||||
| # The final little trick to "correctly" pass the exit status to the exit trap. | ||||
| { | ||||
|   (exit 0); exit | ||||
| } | ||||
|  | ||||
| # Local variables: | ||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||
|   | ||||
| @@ -1,40 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CONFSRC=example.conf | ||||
| CONFDEST=lvm.conf | ||||
|  | ||||
| PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile | ||||
| PROFILES=$(PROFILE_TEMPLATES) $(srcdir)/thin-generic.profile $(srcdir)/thin-performance.profile | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_conf: $(CONFSRC) | ||||
| 	@if [ ! -e $(confdir)/$(CONFDEST) ]; then \ | ||||
| 		echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST)"; \ | ||||
| 		$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST); \ | ||||
| 	fi | ||||
|  | ||||
| install_profiles: $(PROFILES) | ||||
| 	$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_PROFILE_DIR) | ||||
| 	$(INSTALL_DATA) $(PROFILES) $(DESTDIR)$(DEFAULT_PROFILE_DIR)/ | ||||
|  | ||||
| install_lvm2: install_conf install_profiles | ||||
|  | ||||
| install: install_lvm2 | ||||
|  | ||||
| DISTCLEAN_TARGETS += $(CONFSRC) $(PROFILE_TEMPLATES) | ||||
| @@ -1,48 +0,0 @@ | ||||
| # This is a command profile template for the LVM2 system. | ||||
| # | ||||
| # It contains all configuration settings that are customizable by command | ||||
| # profiles. To create a new command profile, select the settings you want | ||||
| # to customize and add them in a new file named <profile_name>.profile. | ||||
| # Then install the new profile in a directory as defined by config/profile_dir | ||||
| # setting found in @DEFAULT_SYS_DIR@/lvm.conf file. | ||||
| # | ||||
| # Command profiles can be referenced by using the --commandprofile option then. | ||||
| # | ||||
| # Refer to 'man lvm.conf' for further information about profiles and | ||||
| # general configuration file layout. | ||||
| # | ||||
| global { | ||||
| 	units="h" | ||||
| 	si_unit_consistency=1 | ||||
| 	suffix=1 | ||||
| 	lvdisplay_shows_full_device_path=0 | ||||
| } | ||||
| report { | ||||
| 	aligned=1 | ||||
| 	buffered=1 | ||||
| 	headings=1 | ||||
| 	separator=" " | ||||
| 	list_item_separator="," | ||||
| 	prefixes=0 | ||||
| 	quoted=1 | ||||
| 	colums_as_rows=0 | ||||
| 	binary_values_as_numeric=0 | ||||
| 	devtypes_sort="devtype_name" | ||||
| 	devtypes_cols="devtype_name,devtype_max_partitions,devtype_description" | ||||
| 	devtypes_cols_verbose="devtype_name,devtype_max_partitions,devtype_description" | ||||
| 	lvs_sort="vg_name,lv_name" | ||||
| 	lvs_cols="lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv" | ||||
| 	lvs_cols_verbose="lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,pool_lv,origin,data_percent,metadata_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid,lv_profile" | ||||
| 	vgs_sort="vg_name" | ||||
| 	vgs_cols="vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free" | ||||
| 	vgs_cols_verbose="vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid,vg_profile" | ||||
| 	pvs_sort="pv_name" | ||||
| 	pvs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free" | ||||
| 	pvs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid" | ||||
| 	segs_sort="vg_name,lv_name,seg_start" | ||||
| 	segs_cols="lv_name,vg_name,lv_attr,stripes,segtype,seg_size" | ||||
| 	segs_cols_verbose="lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize" | ||||
| 	pvsegs_sort="pv_name,pvseg_start" | ||||
| 	pvsegs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size" | ||||
| 	pvsegs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges" | ||||
| } | ||||
							
								
								
									
										1263
									
								
								conf/example.conf.in
									
									
									
									
									
								
							
							
						
						
									
										1263
									
								
								conf/example.conf.in
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,24 +0,0 @@ | ||||
| # This is a metadata profile template for the LVM2 system. | ||||
| # | ||||
| # It contains all configuration settings that are customizable by metadata | ||||
| # profiles. To create a new metadata profile, select the settings you want | ||||
| # to customize and add them in a new file named <profile_name>.profile. | ||||
| # Then install the new profile in a directory as defined by config/profile_dir | ||||
| # setting found in @DEFAULT_SYS_DIR@/lvm.conf file. | ||||
| # | ||||
| # Metadata profiles can be referenced by using the --metadataprofile LVM2 | ||||
| # command line option. | ||||
| # | ||||
| # Refer to 'man lvm.conf' for further information about profiles and | ||||
| # general configuration file layout. | ||||
| # | ||||
| allocation { | ||||
| 	thin_pool_zero=1 | ||||
| 	thin_pool_discards="passdown" | ||||
| 	thin_pool_chunk_size_policy="generic" | ||||
| #	thin_pool_chunk_size=64 | ||||
| } | ||||
| activation { | ||||
| 	thin_pool_autoextend_threshold=100 | ||||
| 	thin_pool_autoextend_percent=20 | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| allocation { | ||||
| 	thin_pool_chunk_size_policy = "generic" | ||||
| 	thin_pool_zero = 1 | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| allocation { | ||||
| 	thin_pool_chunk_size_policy = "performance" | ||||
| 	thin_pool_zero = 0 | ||||
| } | ||||
							
								
								
									
										2056
									
								
								configure.in
									
									
									
									
									
								
							
							
						
						
									
										2056
									
								
								configure.in
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,47 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| .PHONY: dmeventd clvmd cmirrord lvmetad | ||||
|  | ||||
| ifneq ("@CLVMD@", "none") | ||||
|   SUBDIRS += clvmd | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_CMIRRORD@", "yes") | ||||
|   SUBDIRS += cmirrord | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_DMEVENTD@", "yes") | ||||
|   SUBDIRS += dmeventd | ||||
| ifneq ("$(CFLOW_CMD)", "") | ||||
| daemons.cflow: dmeventd.cflow | ||||
| endif | ||||
| endif | ||||
|  | ||||
| ifeq ("@BUILD_LVMETAD@", "yes") | ||||
|   SUBDIRS += lvmetad | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = clvmd cmirrord dmeventd lvmetad | ||||
| endif | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| ifeq ("@BUILD_DMEVENTD@", "yes") | ||||
| device-mapper: dmeventd.device-mapper | ||||
| endif | ||||
| @@ -1,107 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CMAN_LIBS = @CMAN_LIBS@ | ||||
| CMAN_CFLAGS = @CMAN_CFLAGS@ | ||||
| CMAP_LIBS = @CMAP_LIBS@ | ||||
| CMAP_CFLAGS = @CMAP_CFLAGS@ | ||||
| CONFDB_LIBS = @CONFDB_LIBS@ | ||||
| CONFDB_CFLAGS = @CONFDB_CFLAGS@ | ||||
| CPG_LIBS = @CPG_LIBS@ | ||||
| CPG_CFLAGS = @CPG_CFLAGS@ | ||||
| DLM_LIBS = @DLM_LIBS@ | ||||
| DLM_CFLAGS = @DLM_CFLAGS@ | ||||
| QUORUM_LIBS = @QUORUM_LIBS@ | ||||
| QUORUM_CFLAGS = @QUORUM_CFLAGS@ | ||||
| SALCK_LIBS = @SALCK_LIBS@ | ||||
| SALCK_CFLAGS = @SALCK_CFLAGS@ | ||||
|  | ||||
| SOURCES = \ | ||||
| 	clvmd-command.c  \ | ||||
| 	clvmd.c          \ | ||||
| 	lvm-functions.c  \ | ||||
| 	refresh_clvmd.c | ||||
|  | ||||
| ifeq ("@DEBUG@", "yes") | ||||
| 	DEFS += -DDEBUG | ||||
| endif | ||||
|  | ||||
| ifneq (,$(findstring cman,, "@CLVMD@,")) | ||||
| 	SOURCES += clvmd-cman.c | ||||
| 	LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS) | ||||
| 	CFLAGS += $(CMAN_CFLAGS) $(CONFDB_CFLAGS) $(DLM_CFLAGS) | ||||
| 	DEFS += -DUSE_CMAN | ||||
| endif | ||||
|  | ||||
| ifneq (,$(findstring openais,, "@CLVMD@,")) | ||||
| 	SOURCES += clvmd-openais.c | ||||
| 	LMLIBS += $(CONFDB_LIBS) $(CPG_LIBS) $(SALCK_LIBS) | ||||
| 	CFLAGS += $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(SALCK_CFLAGS) | ||||
| 	DEFS += -DUSE_OPENAIS | ||||
| endif | ||||
|  | ||||
| ifneq (,$(findstring corosync,, "@CLVMD@,")) | ||||
| 	SOURCES += clvmd-corosync.c | ||||
| 	LMLIBS += $(CMAP_LIBS) $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS) | ||||
| 	CFLAGS += $(CMAP_CFLAGS) $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS) | ||||
| 	DEFS += -DUSE_COROSYNC | ||||
| endif | ||||
|  | ||||
| ifneq (,$(findstring singlenode,, "@CLVMD@,")) | ||||
| 	SOURCES += clvmd-singlenode.c | ||||
| 	DEFS += -DUSE_SINGLENODE | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
| 	SOURCES += clvmd-cman.c | ||||
| 	SOURCES += clvmd-openais.c | ||||
| 	SOURCES += clvmd-corosync.c | ||||
| 	SOURCES += clvmd-singlenode.c | ||||
| endif | ||||
|  | ||||
| TARGETS = \ | ||||
| 	clvmd | ||||
|  | ||||
| LVMLIBS = $(LVMINTERNAL_LIBS) | ||||
|  | ||||
| ifeq ("@DMEVENTD@", "yes") | ||||
| 	LVMLIBS += -ldevmapper-event | ||||
| endif | ||||
|   | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LVMLIBS += -ldevmapper | ||||
| LIBS += $(PTHREAD_LIBS) | ||||
|  | ||||
| CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS) | ||||
| LDFLAGS += $(EXTRA_EXEC_LDFLAGS) | ||||
|  | ||||
| INSTALL_TARGETS = \ | ||||
| 	install_clvmd | ||||
|  | ||||
| clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a | ||||
| 	$(CC) $(CFLAGS) $(LDFLAGS) -o clvmd $(OBJECTS) \ | ||||
| 		$(LVMLIBS) $(LMLIBS) $(LIBS) | ||||
|  | ||||
| .PHONY: install_clvmd | ||||
|  | ||||
| install_clvmd: $(TARGETS) | ||||
| 	$(INSTALL_PROGRAM) -D clvmd $(usrsbindir)/clvmd | ||||
|  | ||||
| install: $(INSTALL_TARGETS) | ||||
|  | ||||
| install_cluster: $(INSTALL_TARGETS) | ||||
| @@ -1,83 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* Definitions for CLVMD server and clients */ | ||||
|  | ||||
| /* | ||||
|  * The protocol spoken over the cluster and across the local socket. | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVM_H | ||||
| #define _CLVM_H | ||||
|  | ||||
| #include "configure.h" | ||||
| #include <inttypes.h> | ||||
|  | ||||
| struct clvm_header { | ||||
| 	uint8_t  cmd;	        /* See below */ | ||||
| 	uint8_t  flags;	        /* See below */ | ||||
| 	uint16_t xid;	        /* Transaction ID */ | ||||
| 	uint32_t clientid;	/* Only used in Daemon->Daemon comms */ | ||||
| 	int32_t  status;	/* For replies, whether request succeeded */ | ||||
| 	uint32_t arglen;	/* Length of argument below. | ||||
| 				   If >1500 then it will be passed | ||||
| 				   around the cluster in the system LV */ | ||||
| 	char node[1];		/* Actually a NUL-terminated string, node name. | ||||
| 				   If this is empty then the command is | ||||
| 				   forwarded to all cluster nodes unless | ||||
| 				   FLAG_LOCAL or FLAG_REMOTE is also set. */ | ||||
| 	char args[1];		/* Arguments for the command follow the | ||||
| 				   node name, This member is only | ||||
| 				   valid if the node name is empty */ | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
| /* Flags */ | ||||
| #define CLVMD_FLAG_LOCAL	1	/* Only do this on the local node */ | ||||
| #define CLVMD_FLAG_SYSTEMLV	2	/* Data in system LV under my node name */ | ||||
| #define CLVMD_FLAG_NODEERRS	4	/* Reply has errors in node-specific portion */ | ||||
| #define CLVMD_FLAG_REMOTE	8	/* Do this on all nodes except for the local node */ | ||||
|  | ||||
| /* Name of the local socket to communicate between lvm and clvmd */ | ||||
| static const char CLVMD_SOCKNAME[]= DEFAULT_RUN_DIR "/clvmd.sock"; | ||||
|  | ||||
| /* Internal commands & replies */ | ||||
| #define CLVMD_CMD_REPLY    1 | ||||
| #define CLVMD_CMD_VERSION  2	/* Send version around cluster when we start */ | ||||
| #define CLVMD_CMD_GOAWAY   3	/* Die if received this - we are running | ||||
| 				   an incompatible version */ | ||||
| #define CLVMD_CMD_TEST     4	/* Just for mucking about */ | ||||
|  | ||||
| #define CLVMD_CMD_LOCK              30 | ||||
| #define CLVMD_CMD_UNLOCK            31 | ||||
|  | ||||
| /* Lock/Unlock commands */ | ||||
| #define CLVMD_CMD_LOCK_LV           50 | ||||
| #define CLVMD_CMD_LOCK_VG           51 | ||||
| #define CLVMD_CMD_LOCK_QUERY	    52 | ||||
|  | ||||
| /* Misc functions */ | ||||
| #define CLVMD_CMD_REFRESH	    40 | ||||
| #define CLVMD_CMD_GET_CLUSTERNAME   41 | ||||
| #define CLVMD_CMD_SET_DEBUG	    42 | ||||
| #define CLVMD_CMD_VG_BACKUP	    43 | ||||
| #define CLVMD_CMD_RESTART	    44 | ||||
| #define CLVMD_CMD_SYNC_NAMES	    45 | ||||
|  | ||||
| /* Used internally by some callers, but not part of the protocol.*/ | ||||
| #define NODE_ALL	"*" | ||||
| #define NODE_LOCAL	"." | ||||
| #define NODE_REMOTE	"^" | ||||
|  | ||||
| #endif | ||||
| @@ -1,505 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * CMAN communication layer for clvmd. | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| #include <libdlm.h> | ||||
|  | ||||
| #include <syslog.h> | ||||
|  | ||||
| #define LOCKSPACE_NAME "clvmd" | ||||
|  | ||||
| struct clvmd_node | ||||
| { | ||||
| 	struct cman_node *node; | ||||
| 	int clvmd_up; | ||||
| }; | ||||
|  | ||||
| static int num_nodes; | ||||
| static struct cman_node *nodes = NULL; | ||||
| static struct cman_node this_node; | ||||
| static int count_nodes; /* size of allocated nodes array */ | ||||
| static struct dm_hash_table *node_updown_hash; | ||||
| static dlm_lshandle_t *lockspace; | ||||
| static cman_handle_t c_handle; | ||||
|  | ||||
| static void count_clvmds_running(void); | ||||
| static void get_members(void); | ||||
| static int nodeid_from_csid(const char *csid); | ||||
| static int name_from_nodeid(int nodeid, char *name); | ||||
| static void event_callback(cman_handle_t handle, void *private, int reason, int arg); | ||||
| static void data_callback(cman_handle_t handle, void *private, | ||||
| 			  char *buf, int len, uint8_t port, int nodeid); | ||||
|  | ||||
| struct lock_wait { | ||||
| 	pthread_cond_t cond; | ||||
| 	pthread_mutex_t mutex; | ||||
| 	struct dlm_lksb lksb; | ||||
| }; | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	node_updown_hash = dm_hash_create(100); | ||||
|  | ||||
| 	/* Open the cluster communication socket */ | ||||
| 	c_handle = cman_init(NULL); | ||||
| 	if (!c_handle) { | ||||
| 		syslog(LOG_ERR, "Can't open cluster manager socket: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	DEBUGLOG("Connected to CMAN\n"); | ||||
|  | ||||
| 	if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) { | ||||
| 		syslog(LOG_ERR, "Can't bind cluster socket: %m"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (cman_start_notification(c_handle, event_callback)) { | ||||
| 		syslog(LOG_ERR, "Can't start cluster event listening"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Get the cluster members list */ | ||||
| 	get_members(); | ||||
| 	count_clvmds_running(); | ||||
|  | ||||
| 	DEBUGLOG("CMAN initialisation complete\n"); | ||||
|  | ||||
| 	/* Create a lockspace for LV & VG locks to live in */ | ||||
| 	lockspace = dlm_open_lockspace(LOCKSPACE_NAME); | ||||
| 	if (!lockspace) { | ||||
| 		lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600); | ||||
| 		if (!lockspace) { | ||||
| 			syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		DEBUGLOG("Created DLM lockspace for CLVMD.\n"); | ||||
| 	} else | ||||
| 		DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n"); | ||||
|  | ||||
| 	dlm_ls_pthread_init(lockspace); | ||||
| 	DEBUGLOG("DLM initialisation complete\n"); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_init_completed(void) | ||||
| { | ||||
| 	clvmd_cluster_init_completed(); | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd(void) | ||||
| { | ||||
| 	return cman_get_fd(c_handle); | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes(void) | ||||
| { | ||||
| 	int i; | ||||
| 	int nnodes = 0; | ||||
|  | ||||
| 	/* return number of ACTIVE nodes */ | ||||
| 	for (i=0; i<num_nodes; i++) { | ||||
| 		if (nodes[i].cn_member && nodes[i].cn_nodeid) | ||||
| 			nnodes++; | ||||
| 	} | ||||
| 	return nnodes; | ||||
| } | ||||
|  | ||||
| /* send_message with the fd check removed */ | ||||
| static int _cluster_send_message(const void *buf, int msglen, const char *csid, | ||||
| 				 const char *errtext) | ||||
| { | ||||
| 	int nodeid = 0; | ||||
|  | ||||
| 	if (csid) | ||||
| 		memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN); | ||||
|  | ||||
| 	if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0) | ||||
| 	{ | ||||
| 		log_error("%s", errtext); | ||||
| 	} | ||||
| 	return msglen; | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	if (this_node.cn_nodeid == 0) { | ||||
| 		cman_get_node(c_handle, 0, &this_node); | ||||
| 	} | ||||
| 	memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN); | ||||
| } | ||||
|  | ||||
| /* Call a callback routine for each node is that known (down means not running a clvmd) */ | ||||
| static int _cluster_do_node_callback(struct local_client *client, | ||||
| 				     void (*callback) (struct local_client *, | ||||
| 						       const char *, | ||||
| 						       int)) | ||||
| { | ||||
| 	int i; | ||||
| 	int somedown = 0; | ||||
|  | ||||
| 	for (i = 0; i < _get_num_nodes(); i++) { | ||||
| 		if (nodes[i].cn_member && nodes[i].cn_nodeid) { | ||||
| 			int up = (int)(long)dm_hash_lookup_binary(node_updown_hash, (char *)&nodes[i].cn_nodeid, sizeof(int)); | ||||
|  | ||||
| 			callback(client, (char *)&nodes[i].cn_nodeid, up); | ||||
| 			if (!up) | ||||
| 				somedown = -1; | ||||
| 		} | ||||
| 	} | ||||
| 	return somedown; | ||||
| } | ||||
|  | ||||
| /* Process OOB messages from the cluster socket */ | ||||
| static void event_callback(cman_handle_t handle, void *private, int reason, int arg) | ||||
| { | ||||
| 	char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
|  | ||||
| 	switch (reason) { | ||||
|         case CMAN_REASON_PORTCLOSED: | ||||
| 		name_from_nodeid(arg, namebuf); | ||||
| 		log_notice("clvmd on node %s has died\n", namebuf); | ||||
| 		DEBUGLOG("Got port closed message, removing node %s\n", namebuf); | ||||
|  | ||||
| 		dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0); | ||||
| 		break; | ||||
|  | ||||
| 	case CMAN_REASON_STATECHANGE: | ||||
| 		DEBUGLOG("Got state change message, re-reading members list\n"); | ||||
| 		get_members(); | ||||
| 		break; | ||||
|  | ||||
| #if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2 | ||||
| 	case CMAN_REASON_PORTOPENED: | ||||
| 		/* Ignore this, wait for startup message from clvmd itself */ | ||||
| 		break; | ||||
|  | ||||
| 	case CMAN_REASON_TRY_SHUTDOWN: | ||||
| 		DEBUGLOG("Got try shutdown, sending OK\n"); | ||||
| 		cman_replyto_shutdown(c_handle, 1); | ||||
| 		break; | ||||
| #endif | ||||
| 	default: | ||||
| 		/* ERROR */ | ||||
| 		DEBUGLOG("Got unknown event callback message: %d\n", reason); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static struct local_client *cman_client; | ||||
| static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, | ||||
| 				const char *csid, | ||||
| 				struct local_client **new_client) | ||||
| { | ||||
|  | ||||
| 	/* Save this for data_callback */ | ||||
| 	cman_client = fd; | ||||
|  | ||||
| 	/* We never return a new client */ | ||||
| 	*new_client = NULL; | ||||
|  | ||||
| 	return cman_dispatch(c_handle, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void data_callback(cman_handle_t handle, void *private, | ||||
| 			  char *buf, int len, uint8_t port, int nodeid) | ||||
| { | ||||
| 	/* Ignore looped back messages */ | ||||
| 	if (nodeid == this_node.cn_nodeid) | ||||
| 		return; | ||||
| 	process_message(cman_client, buf, len, (char *)&nodeid); | ||||
| } | ||||
|  | ||||
| static void _add_up_node(const char *csid) | ||||
| { | ||||
| 	/* It's up ! */ | ||||
| 	int nodeid = nodeid_from_csid(csid); | ||||
|  | ||||
| 	dm_hash_insert_binary(node_updown_hash, (char *)&nodeid, sizeof(int), (void *)1); | ||||
| 	DEBUGLOG("Added new node %d to updown list\n", nodeid); | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown(void) | ||||
| { | ||||
| 	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); | ||||
| 	cman_finish(c_handle); | ||||
| } | ||||
|  | ||||
| static int is_listening(int nodeid) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	do { | ||||
| 		status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD); | ||||
| 		if (status < 0 && errno == EBUSY) {	/* Don't busywait */ | ||||
| 			sleep(1); | ||||
| 			errno = EBUSY;	/* In case sleep trashes it */ | ||||
| 		} | ||||
| 	} | ||||
| 	while (status < 0 && errno == EBUSY); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Populate the list of CLVMDs running. | ||||
|    called only at startup time */ | ||||
| static void count_clvmds_running(void) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		int nodeid = nodes[i].cn_nodeid; | ||||
|  | ||||
| 		if (is_listening(nodeid) == 1) | ||||
| 			dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1); | ||||
| 		else | ||||
| 			dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Get a list of active cluster members */ | ||||
| static void get_members(void) | ||||
| { | ||||
| 	int retnodes; | ||||
| 	int status; | ||||
| 	int i; | ||||
| 	int high_nodeid = 0; | ||||
|  | ||||
| 	num_nodes = cman_get_node_count(c_handle); | ||||
| 	if (num_nodes == -1) { | ||||
| 		log_error("Unable to get node count"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* Not enough room for new nodes list ? */ | ||||
| 	if (num_nodes > count_nodes && nodes) { | ||||
| 		free(nodes); | ||||
| 		nodes = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (nodes == NULL) { | ||||
| 		count_nodes = num_nodes + 10; /* Overallocate a little */ | ||||
| 		nodes = malloc(count_nodes * sizeof(struct cman_node)); | ||||
| 		if (!nodes) { | ||||
| 			log_error("Unable to allocate nodes array\n"); | ||||
| 			exit(5); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes); | ||||
| 	if (status < 0) { | ||||
| 		log_error("Unable to get node details"); | ||||
| 		exit(6); | ||||
| 	} | ||||
|  | ||||
| 	/* Get the highest nodeid */ | ||||
| 	for (i=0; i<retnodes; i++) { | ||||
| 		if (nodes[i].cn_nodeid > high_nodeid) | ||||
| 			high_nodeid = nodes[i].cn_nodeid; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Convert a node name to a CSID */ | ||||
| static int _csid_from_name(char *csid, const char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (strcmp(name, nodes[i].cn_name) == 0) { | ||||
| 			memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a CSID to a node name */ | ||||
| static int _name_from_csid(const char *csid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) { | ||||
| 			strcpy(name, nodes[i].cn_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Who?? */ | ||||
| 	strcpy(name, "Unknown"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a node ID to a node name */ | ||||
| static int name_from_nodeid(int nodeid, char *name) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num_nodes; i++) { | ||||
| 		if (nodeid == nodes[i].cn_nodeid) { | ||||
| 			strcpy(name, nodes[i].cn_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	/* Who?? */ | ||||
| 	strcpy(name, "Unknown"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* Convert a CSID to a node ID */ | ||||
| static int nodeid_from_csid(const char *csid) | ||||
| { | ||||
|         int nodeid; | ||||
|  | ||||
| 	memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN); | ||||
|  | ||||
| 	return nodeid; | ||||
| } | ||||
|  | ||||
| static int _is_quorate(void) | ||||
| { | ||||
| 	return cman_is_quorate(c_handle); | ||||
| } | ||||
|  | ||||
| static void sync_ast_routine(void *arg) | ||||
| { | ||||
| 	struct lock_wait *lwait = arg; | ||||
|  | ||||
| 	pthread_mutex_lock(&lwait->mutex); | ||||
| 	pthread_cond_signal(&lwait->cond); | ||||
| 	pthread_mutex_unlock(&lwait->mutex); | ||||
| } | ||||
|  | ||||
| static int _sync_lock(const char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	int status; | ||||
| 	struct lock_wait lwait; | ||||
|  | ||||
| 	if (!lockid) { | ||||
| 		errno = EINVAL; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags); | ||||
| 	/* Conversions need the lockid in the LKSB */ | ||||
| 	if (flags & LKF_CONVERT) | ||||
| 		lwait.lksb.sb_lkid = *lockid; | ||||
|  | ||||
| 	pthread_cond_init(&lwait.cond, NULL); | ||||
| 	pthread_mutex_init(&lwait.mutex, NULL); | ||||
| 	pthread_mutex_lock(&lwait.mutex); | ||||
|  | ||||
| 	status = dlm_ls_lock(lockspace, | ||||
| 			     mode, | ||||
| 			     &lwait.lksb, | ||||
| 			     flags, | ||||
| 			     resource, | ||||
| 			     strlen(resource), | ||||
| 			     0, sync_ast_routine, &lwait, NULL, NULL); | ||||
| 	if (status) | ||||
| 		return status; | ||||
|  | ||||
| 	/* Wait for it to complete */ | ||||
| 	pthread_cond_wait(&lwait.cond, &lwait.mutex); | ||||
| 	pthread_mutex_unlock(&lwait.mutex); | ||||
|  | ||||
| 	*lockid = lwait.lksb.sb_lkid; | ||||
|  | ||||
| 	errno = lwait.lksb.sb_status; | ||||
| 	DEBUGLOG("sync_lock: returning lkid %x\n", *lockid); | ||||
| 	if (lwait.lksb.sb_status) | ||||
| 		return -1; | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
|  | ||||
| static int _sync_unlock(const char *resource /* UNUSED */, int lockid) | ||||
| { | ||||
| 	int status; | ||||
| 	struct lock_wait lwait; | ||||
|  | ||||
| 	DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid); | ||||
|  | ||||
| 	pthread_cond_init(&lwait.cond, NULL); | ||||
| 	pthread_mutex_init(&lwait.mutex, NULL); | ||||
| 	pthread_mutex_lock(&lwait.mutex); | ||||
|  | ||||
| 	status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait); | ||||
|  | ||||
| 	if (status) | ||||
| 		return status; | ||||
|  | ||||
| 	/* Wait for it to complete */ | ||||
| 	pthread_cond_wait(&lwait.cond, &lwait.mutex); | ||||
| 	pthread_mutex_unlock(&lwait.mutex); | ||||
|  | ||||
| 	errno = lwait.lksb.sb_status; | ||||
| 	if (lwait.lksb.sb_status != EUNLOCK) | ||||
| 		return -1; | ||||
| 	else | ||||
| 		return 0; | ||||
|  | ||||
| } | ||||
|  | ||||
| static int _get_cluster_name(char *buf, int buflen) | ||||
| { | ||||
| 	cman_cluster_t cluster_info; | ||||
| 	int status; | ||||
|  | ||||
| 	status = cman_get_cluster(c_handle, &cluster_info); | ||||
| 	if (!status) { | ||||
| 		strncpy(buf, cluster_info.ci_name, buflen); | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_cman_ops = { | ||||
| 	.name                     = "cman", | ||||
| 	.cluster_init_completed   = _cluster_init_completed, | ||||
| 	.cluster_send_message     = _cluster_send_message, | ||||
| 	.name_from_csid           = _name_from_csid, | ||||
| 	.csid_from_name           = _csid_from_name, | ||||
| 	.get_num_nodes            = _get_num_nodes, | ||||
| 	.cluster_fd_callback      = _cluster_fd_callback, | ||||
| 	.get_main_cluster_fd      = _get_main_cluster_fd, | ||||
| 	.cluster_do_node_callback = _cluster_do_node_callback, | ||||
| 	.is_quorate               = _is_quorate, | ||||
| 	.get_our_csid             = _get_our_csid, | ||||
| 	.add_up_node              = _add_up_node, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.get_cluster_name         = _get_cluster_name, | ||||
| 	.sync_lock                = _sync_lock, | ||||
| 	.sync_unlock              = _sync_unlock, | ||||
| }; | ||||
|  | ||||
| struct cluster_ops *init_cman_cluster(void) | ||||
| { | ||||
| 	if (!_init_cluster()) | ||||
| 		return &_cluster_cman_ops; | ||||
| 	else | ||||
| 		return NULL; | ||||
| } | ||||
| @@ -1,414 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  | ||||
|   CLVMD Cluster LVM daemon command processor. | ||||
|  | ||||
|   To add commands to the daemon simply add a processor in do_command and return | ||||
|   and messages back in buf and the length in *retlen. The initial value of | ||||
|   buflen is the maximum size of the buffer. if buf is not large enough then it | ||||
|   may be reallocated by the functions in here to a suitable size bearing in | ||||
|   mind that anything larger than the passed-in size will have to be returned | ||||
|   using the system LV and so performance will suffer. | ||||
|  | ||||
|   The status return will be negated and passed back to the originating node. | ||||
|  | ||||
|   pre- and post- command routines are called only on the local node. The | ||||
|   purpose is primarily to get and release locks, though the pre- routine should | ||||
|   also do any other local setups required by the command (if any) and can | ||||
|   return a failure code that prevents the command from being distributed around | ||||
|   the cluster | ||||
|  | ||||
|   The pre- and post- routines are run in their own thread so can block as long | ||||
|   they like, do_command is run in the main clvmd thread so should not block for | ||||
|   too long. If the pre-command returns an error code (!=0) then the command | ||||
|   will not be propogated around the cluster but the post-command WILL be called | ||||
|  | ||||
|   Also note that the pre and post routine are *always* called on the local | ||||
|   node, even if the command to be executed was only requested to run on a | ||||
|   remote node. It may peek inside the client structure to check the status of | ||||
|   the command. | ||||
|  | ||||
|   The clients of the daemon must, naturally, understand the return messages and | ||||
|   codes. | ||||
|  | ||||
|   Routines in here may only READ the values in the client structure passed in | ||||
|   apart from client->private which they are free to do what they like with. | ||||
|  | ||||
| */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-globals.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| #include "locking.h" | ||||
|  | ||||
| #include <sys/utsname.h> | ||||
|  | ||||
| extern struct cluster_ops *clops; | ||||
| static int restart_clvmd(void); | ||||
|  | ||||
| /* This is where all the real work happens: | ||||
|    NOTE: client will be NULL when this is executed on a remote node */ | ||||
| int do_command(struct local_client *client, struct clvm_header *msg, int msglen, | ||||
| 	       char **buf, int buflen, int *retlen) | ||||
| { | ||||
| 	char *args = msg->node + strlen(msg->node) + 1; | ||||
| 	int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node); | ||||
| 	int status = 0; | ||||
| 	char *lockname; | ||||
| 	const char *locktype; | ||||
| 	struct utsname nodeinfo; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
|  | ||||
| 	/* Do the command */ | ||||
| 	switch (msg->cmd) { | ||||
| 		/* Just a test message */ | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		if (arglen > buflen) { | ||||
| 			char *new_buf; | ||||
| 			buflen = arglen + 200; | ||||
| 			new_buf = realloc(*buf, buflen); | ||||
| 			if (new_buf == NULL) { | ||||
| 				status = errno; | ||||
| 				free (*buf); | ||||
| 			} | ||||
| 			*buf = new_buf; | ||||
| 		} | ||||
| 		if (*buf) { | ||||
| 			if (uname(&nodeinfo)) | ||||
| 				memset(&nodeinfo, 0, sizeof(nodeinfo)); | ||||
|  | ||||
| 			*retlen = 1 + dm_snprintf(*buf, buflen, | ||||
| 						  "TEST from %s: %s v%s", | ||||
| 						  nodeinfo.nodename, args, | ||||
| 						  nodeinfo.release); | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 		lock_cmd = args[0]; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		/* Check to see if the VG is in use by LVM1 */ | ||||
| 		status = do_check_lvm1(lockname); | ||||
| 		do_lock_vg(lock_cmd, lock_flags, lockname); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		/* This is the biggie */ | ||||
| 		lock_cmd = args[0]; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = do_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		/* Replace EIO with something less scary */ | ||||
| 		if (status == EIO) { | ||||
| 			*retlen = 1 + dm_snprintf(*buf, buflen, "%s", | ||||
| 						  get_last_lvm_error()); | ||||
| 			return EIO; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_QUERY: | ||||
| 		lockname = &args[2]; | ||||
| 		if (buflen < 3) | ||||
| 			return EIO; | ||||
| 		if ((locktype = do_lock_query(lockname))) | ||||
| 			*retlen = 1 + dm_snprintf(*buf, buflen, "%s", locktype); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_REFRESH: | ||||
| 		do_refresh_cache(); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_SYNC_NAMES: | ||||
| 		lvm_do_fs_unlock(); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_SET_DEBUG: | ||||
| 		clvmd_set_debug((debug_t) args[0]); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_RESTART: | ||||
| 		status = restart_clvmd(); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_GET_CLUSTERNAME: | ||||
| 		status = clops->get_cluster_name(*buf, buflen); | ||||
| 		if (!status) | ||||
| 			*retlen = strlen(*buf)+1; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_VG_BACKUP: | ||||
| 		/* | ||||
| 		 * Do not run backup on local node, caller should do that. | ||||
| 		 */ | ||||
| 		if (!client) | ||||
| 			lvm_do_backup(&args[2]); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		/* Won't get here because command is validated in pre_command */ | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	/* Check the status of the command and return the error text */ | ||||
| 	if (status) { | ||||
| 		*retlen = 1 + ((*buf) ? dm_snprintf(*buf, buflen, "%s", | ||||
| 						    strerror(status)) : -1); | ||||
| 	} | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| static int lock_vg(struct local_client *client) | ||||
| { | ||||
| 	struct dm_hash_table *lock_hash; | ||||
| 	struct clvm_header *header = | ||||
| 		(struct clvm_header *) client->bits.localsock.cmd; | ||||
| 	unsigned char lock_cmd; | ||||
| 	int lock_mode; | ||||
| 	char *args = header->node + strlen(header->node) + 1; | ||||
| 	int lkid; | ||||
| 	int status; | ||||
| 	char *lockname; | ||||
|  | ||||
| 	/* | ||||
| 	 * Keep a track of VG locks in our own hash table. In current | ||||
| 	 * practice there should only ever be more than two VGs locked | ||||
| 	 * if a user tries to merge lots of them at once | ||||
| 	 */ | ||||
| 	if (!client->bits.localsock.private) { | ||||
| 		if (!(lock_hash = dm_hash_create(3))) | ||||
| 			return ENOMEM; | ||||
| 		client->bits.localsock.private = (void *) lock_hash; | ||||
| 	} else | ||||
| 		lock_hash = (struct dm_hash_table *) client->bits.localsock.private; | ||||
|  | ||||
| 	lock_cmd = args[0] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK); | ||||
| 	lock_mode = ((int) lock_cmd & LCK_TYPE_MASK); | ||||
| 	/* lock_flags = args[1]; */ | ||||
| 	lockname = &args[2]; | ||||
| 	DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client); | ||||
|  | ||||
| 	if (lock_mode == LCK_UNLOCK) { | ||||
| 		if (!(lkid = (int) (long) dm_hash_lookup(lock_hash, lockname))) | ||||
| 			return EINVAL; | ||||
|  | ||||
| 		if ((status = sync_unlock(lockname, lkid))) | ||||
| 			status = errno; | ||||
| 		else | ||||
| 			dm_hash_remove(lock_hash, lockname); | ||||
| 	} else { | ||||
| 		/* Read locks need to be PR; other modes get passed through */ | ||||
| 		if (lock_mode == LCK_READ) | ||||
| 			lock_mode = LCK_PREAD; | ||||
|  | ||||
| 		if ((status = sync_lock(lockname, lock_mode, (lock_cmd & LCK_NONBLOCK) ? LCKF_NOQUEUE : 0, &lkid))) | ||||
| 			status = errno; | ||||
| 		else if (!dm_hash_insert(lock_hash, lockname, (void *) (long) lkid)) | ||||
| 			return ENOMEM; | ||||
| 	} | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Pre-command is a good place to get locks that are needed only for the duration | ||||
|    of the commands around the cluster (don't forget to free them in post-command), | ||||
|    and to sanity check the command arguments */ | ||||
| int do_pre_command(struct local_client *client) | ||||
| { | ||||
| 	struct clvm_header *header = | ||||
| 	    (struct clvm_header *) client->bits.localsock.cmd; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
| 	char *args = header->node + strlen(header->node) + 1; | ||||
| 	int lockid = 0; | ||||
| 	int status = 0; | ||||
| 	char *lockname; | ||||
|  | ||||
| 	switch (header->cmd) { | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		status = sync_lock("CLVMD_TEST", LCK_EXCL, 0, &lockid); | ||||
| 		client->bits.localsock.private = (void *)(long)lockid; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 		lockname = &args[2]; | ||||
| 		/* We take out a real lock unless LCK_CACHE was set */ | ||||
| 		if (!strncmp(lockname, "V_", 2) || | ||||
| 		    !strncmp(lockname, "P_#", 3)) | ||||
| 			status = lock_vg(client); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		lock_cmd = args[0]; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = pre_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_REFRESH: | ||||
| 	case CLVMD_CMD_GET_CLUSTERNAME: | ||||
| 	case CLVMD_CMD_SET_DEBUG: | ||||
| 	case CLVMD_CMD_VG_BACKUP: | ||||
| 	case CLVMD_CMD_SYNC_NAMES: | ||||
| 	case CLVMD_CMD_LOCK_QUERY: | ||||
| 	case CLVMD_CMD_RESTART: | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		log_error("Unknown command %d received\n", header->cmd); | ||||
| 		status = EINVAL; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Note that the post-command routine is called even if the pre-command or the real command | ||||
|    failed */ | ||||
| int do_post_command(struct local_client *client) | ||||
| { | ||||
| 	struct clvm_header *header = | ||||
| 	    (struct clvm_header *) client->bits.localsock.cmd; | ||||
| 	int status = 0; | ||||
| 	unsigned char lock_cmd; | ||||
| 	unsigned char lock_flags; | ||||
| 	char *args = header->node + strlen(header->node) + 1; | ||||
| 	char *lockname; | ||||
|  | ||||
| 	switch (header->cmd) { | ||||
| 	case CLVMD_CMD_TEST: | ||||
| 		status = sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private); | ||||
| 		client->bits.localsock.private = NULL; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_LV: | ||||
| 		lock_cmd = args[0]; | ||||
| 		lock_flags = args[1]; | ||||
| 		lockname = &args[2]; | ||||
| 		status = post_lock_lv(lock_cmd, lock_flags, lockname); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		/* Nothing to do here */ | ||||
| 		break; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Called when the client is about to be deleted */ | ||||
| void cmd_client_cleanup(struct local_client *client) | ||||
| { | ||||
| 	struct dm_hash_node *v; | ||||
| 	struct dm_hash_table *lock_hash; | ||||
| 	int lkid; | ||||
| 	char *lockname; | ||||
|  | ||||
| 	if (!client->bits.localsock.private) | ||||
| 		return; | ||||
|  | ||||
| 	lock_hash = (struct dm_hash_table *)client->bits.localsock.private; | ||||
|  | ||||
| 	dm_hash_iterate(v, lock_hash) { | ||||
| 		lkid = (int)(long)dm_hash_get_data(lock_hash, v); | ||||
| 		lockname = dm_hash_get_key(lock_hash, v); | ||||
| 		DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid); | ||||
| 		(void) sync_unlock(lockname, lkid); | ||||
| 	} | ||||
|  | ||||
| 	dm_hash_destroy(lock_hash); | ||||
| 	client->bits.localsock.private = NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int restart_clvmd(void) | ||||
| { | ||||
| 	const char **argv; | ||||
| 	char *lv_name; | ||||
| 	int argc = 0, max_locks = 0; | ||||
| 	struct dm_hash_node *hn = NULL; | ||||
| 	char debug_arg[16]; | ||||
| 	const char *clvmd = getenv("LVM_CLVMD_BINARY") ? : CLVMD_PATH; | ||||
|  | ||||
| 	DEBUGLOG("clvmd restart requested\n"); | ||||
|  | ||||
| 	/* Count exclusively-open LVs */ | ||||
| 	do { | ||||
| 		hn = get_next_excl_lock(hn, &lv_name); | ||||
| 		if (lv_name) { | ||||
| 			max_locks++; | ||||
| 			if (!*lv_name) | ||||
| 				break; /* FIXME: Is this error ? */ | ||||
| 		} | ||||
| 	} while (hn); | ||||
|  | ||||
| 	/* clvmd + locks (-E uuid) + debug (-d X) + NULL */ | ||||
| 	if (!(argv = malloc((max_locks * 2 + 6) * sizeof(*argv)))) | ||||
| 		goto_out; | ||||
|  | ||||
| 	/* | ||||
| 	 * Build the command-line | ||||
| 	 */ | ||||
| 	argv[argc++] = "clvmd"; | ||||
|  | ||||
| 	/* Propagate debug options */ | ||||
| 	if (clvmd_get_debug()) { | ||||
| 		if (dm_snprintf(debug_arg, sizeof(debug_arg), "-d%u", clvmd_get_debug()) < 0) | ||||
| 			goto_out; | ||||
| 		argv[argc++] = debug_arg; | ||||
| 	} | ||||
|  | ||||
| 	/* Propagate foreground options */ | ||||
| 	if (clvmd_get_foreground()) | ||||
| 		argv[argc++] = "-f"; | ||||
|  | ||||
| 	argv[argc++] = "-I"; | ||||
| 	argv[argc++] = clops->name; | ||||
|  | ||||
| 	/* Now add the exclusively-open LVs */ | ||||
| 	hn = NULL; | ||||
| 	do { | ||||
| 		hn = get_next_excl_lock(hn, &lv_name); | ||||
| 		if (lv_name) { | ||||
| 			if (!*lv_name) | ||||
| 				break; /* FIXME: Is this error ? */ | ||||
| 			argv[argc++] = "-E"; | ||||
| 			argv[argc++] = lv_name; | ||||
| 			DEBUGLOG("excl lock: %s\n", lv_name); | ||||
| 		} | ||||
| 	} while (hn); | ||||
| 	argv[argc] = NULL; | ||||
|  | ||||
| 	/* Exec new clvmd */ | ||||
| 	DEBUGLOG("--- Restarting %s ---\n", clvmd); | ||||
| 	for (argc = 1; argv[argc]; argc++) DEBUGLOG("--- %d: %s\n", argc, argv[argc]); | ||||
|  | ||||
| 	/* NOTE: This will fail when downgrading! */ | ||||
| 	execvp(clvmd, (char **)argv); | ||||
| out: | ||||
| 	/* We failed */ | ||||
| 	DEBUGLOG("Restart of clvmd failed.\n"); | ||||
|  | ||||
| 	free(argv); | ||||
|  | ||||
| 	return EIO; | ||||
| } | ||||
| @@ -1,32 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This file must be included first by every clvmd source file. | ||||
|  */ | ||||
| #ifndef _LVM_CLVMD_COMMON_H | ||||
| #define _LVM_CLVMD_COMMON_H | ||||
|  | ||||
| #include "configure.h" | ||||
|  | ||||
| #define _REENTRANT | ||||
| #define _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include "libdevmapper.h" | ||||
| #include "lvm-logging.h" | ||||
|  | ||||
| #include <unistd.h> | ||||
|  | ||||
| #endif | ||||
| @@ -1,119 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Abstraction layer for clvmd cluster communications | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVMD_COMMS_H | ||||
| #define _CLVMD_COMMS_H | ||||
|  | ||||
| struct local_client; | ||||
|  | ||||
| struct cluster_ops { | ||||
| 	const char *name; | ||||
| 	void (*cluster_init_completed) (void); | ||||
|  | ||||
| 	int (*cluster_send_message) (const void *buf, int msglen, | ||||
| 				     const char *csid, | ||||
| 				     const char *errtext); | ||||
| 	int (*name_from_csid) (const char *csid, char *name); | ||||
| 	int (*csid_from_name) (char *csid, const char *name); | ||||
| 	int (*get_num_nodes) (void); | ||||
| 	int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len, | ||||
| 				    const char *csid, | ||||
| 				    struct local_client **new_client); | ||||
| 	int (*get_main_cluster_fd) (void);	/* gets accept FD or cman cluster socket */ | ||||
| 	int (*cluster_do_node_callback) (struct local_client *client, | ||||
| 					 void (*callback) (struct local_client *, | ||||
| 							   const char *csid, | ||||
| 							   int node_up)); | ||||
| 	int (*is_quorate) (void); | ||||
|  | ||||
| 	void (*get_our_csid) (char *csid); | ||||
| 	void (*add_up_node) (const char *csid); | ||||
| 	void (*reread_config) (void); | ||||
| 	void (*cluster_closedown) (void); | ||||
|  | ||||
| 	int (*get_cluster_name)(char *buf, int buflen); | ||||
|  | ||||
| 	int (*sync_lock) (const char *resource, int mode, | ||||
| 			  int flags, int *lockid); | ||||
| 	int (*sync_unlock) (const char *resource, int lockid); | ||||
|  | ||||
| }; | ||||
|  | ||||
| #ifdef USE_CMAN | ||||
| #  include <netinet/in.h> | ||||
| #  include "libcman.h" | ||||
| #  define CMAN_MAX_CSID_LEN 4 | ||||
| #  ifndef MAX_CSID_LEN | ||||
| #    define MAX_CSID_LEN CMAN_MAX_CSID_LEN | ||||
| #  endif | ||||
| #  undef MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #  define MAX_CLUSTER_MEMBER_NAME_LEN   CMAN_MAX_NODENAME_LEN | ||||
| #  define CMAN_MAX_CLUSTER_MESSAGE 1500 | ||||
| #  define CLUSTER_PORT_CLVMD 11 | ||||
| struct cluster_ops *init_cman_cluster(void); | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_OPENAIS | ||||
| #  include <openais/saAis.h> | ||||
| #  include <corosync/totem/totem.h> | ||||
| #  define OPENAIS_CSID_LEN (sizeof(int)) | ||||
| #  define OPENAIS_MAX_CLUSTER_MESSAGE         MESSAGE_SIZE_MAX | ||||
| #  define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH | ||||
| #  ifndef MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #    define MAX_CLUSTER_MEMBER_NAME_LEN       SA_MAX_NAME_LENGTH | ||||
| #  endif | ||||
| #  ifndef CMAN_MAX_CLUSTER_MESSAGE | ||||
| #    define CMAN_MAX_CLUSTER_MESSAGE          MESSAGE_SIZE_MAX | ||||
| #  endif | ||||
| #  ifndef MAX_CSID_LEN | ||||
| #    define MAX_CSID_LEN sizeof(int) | ||||
| #  endif | ||||
| struct cluster_ops *init_openais_cluster(void); | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_COROSYNC | ||||
| #  include <corosync/corotypes.h> | ||||
| #  define COROSYNC_CSID_LEN (sizeof(int)) | ||||
| #  define COROSYNC_MAX_CLUSTER_MESSAGE         65535 | ||||
| #  define COROSYNC_MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH | ||||
| #  ifndef MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #    define MAX_CLUSTER_MEMBER_NAME_LEN       CS_MAX_NAME_LENGTH | ||||
| #  endif | ||||
| #  ifndef CMAN_MAX_CLUSTER_MESSAGE | ||||
| #    define CMAN_MAX_CLUSTER_MESSAGE          65535 | ||||
| #  endif | ||||
| #  ifndef MAX_CSID_LEN | ||||
| #    define MAX_CSID_LEN sizeof(int) | ||||
| #  endif | ||||
| struct cluster_ops *init_corosync_cluster(void); | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_SINGLENODE | ||||
| #  define SINGLENODE_CSID_LEN (sizeof(int)) | ||||
| #  ifndef MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #    define MAX_CLUSTER_MEMBER_NAME_LEN       64 | ||||
| #  endif | ||||
| #  define SINGLENODE_MAX_CLUSTER_MESSAGE          65535 | ||||
| #  ifndef MAX_CSID_LEN | ||||
| #    define MAX_CSID_LEN sizeof(int) | ||||
| #  endif | ||||
| struct cluster_ops *init_singlenode_cluster(void); | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -1,658 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2009-2012 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This provides the interface between clvmd and corosync/DLM as the cluster | ||||
|  * and lock manager. | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| #include "locking.h" | ||||
|  | ||||
| #include <corosync/cpg.h> | ||||
| #include <corosync/quorum.h> | ||||
|  | ||||
| #ifdef HAVE_COROSYNC_CONFDB_H | ||||
| #  include <corosync/confdb.h> | ||||
| #elif defined HAVE_COROSYNC_CMAP_H | ||||
| #  include <corosync/cmap.h> | ||||
| #else | ||||
| #  error "Either HAVE_COROSYNC_CONFDB_H or HAVE_COROSYNC_CMAP_H must be defined." | ||||
| #endif | ||||
|  | ||||
| #include <libdlm.h> | ||||
|  | ||||
| #include <syslog.h> | ||||
|  | ||||
| /* Timeout value for several corosync calls */ | ||||
| #define LOCKSPACE_NAME "clvmd" | ||||
|  | ||||
| static void corosync_cpg_deliver_callback (cpg_handle_t handle, | ||||
| 				  const struct cpg_name *groupName, | ||||
| 				  uint32_t nodeid, | ||||
| 				  uint32_t pid, | ||||
| 				  void *msg, | ||||
| 				  size_t msg_len); | ||||
| static void corosync_cpg_confchg_callback(cpg_handle_t handle, | ||||
| 				 const struct cpg_name *groupName, | ||||
| 				 const struct cpg_address *member_list, size_t member_list_entries, | ||||
| 				 const struct cpg_address *left_list, size_t left_list_entries, | ||||
| 				 const struct cpg_address *joined_list, size_t joined_list_entries); | ||||
| static void _cluster_closedown(void); | ||||
|  | ||||
| /* Hash list of nodes in the cluster */ | ||||
| static struct dm_hash_table *node_hash; | ||||
|  | ||||
| /* Number of active nodes */ | ||||
| static int num_nodes; | ||||
| static unsigned int our_nodeid; | ||||
|  | ||||
| static struct local_client *cluster_client; | ||||
|  | ||||
| /* Corosync handles */ | ||||
| static cpg_handle_t cpg_handle; | ||||
| static quorum_handle_t quorum_handle; | ||||
|  | ||||
| /* DLM Handle */ | ||||
| static dlm_lshandle_t *lockspace; | ||||
|  | ||||
| static struct cpg_name cpg_group_name; | ||||
|  | ||||
| /* Corosync callback structs */ | ||||
| cpg_callbacks_t corosync_cpg_callbacks = { | ||||
| 	.cpg_deliver_fn =            corosync_cpg_deliver_callback, | ||||
| 	.cpg_confchg_fn =            corosync_cpg_confchg_callback, | ||||
| }; | ||||
|  | ||||
| quorum_callbacks_t quorum_callbacks = { | ||||
| 	.quorum_notify_fn = NULL, | ||||
| }; | ||||
|  | ||||
| struct node_info | ||||
| { | ||||
| 	enum {NODE_DOWN, NODE_CLVMD} state; | ||||
| 	int nodeid; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* Set errno to something approximating the right value and return 0 or -1 */ | ||||
| static int cs_to_errno(cs_error_t err) | ||||
| { | ||||
| 	switch(err) | ||||
| 	{ | ||||
| 	case CS_OK: | ||||
| 		return 0; | ||||
|         case CS_ERR_LIBRARY: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case CS_ERR_VERSION: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case CS_ERR_INIT: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case CS_ERR_TIMEOUT: | ||||
| 		errno = ETIME; | ||||
| 		break; | ||||
|         case CS_ERR_TRY_AGAIN: | ||||
| 		errno = EAGAIN; | ||||
| 		break; | ||||
|         case CS_ERR_INVALID_PARAM: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case CS_ERR_NO_MEMORY: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
|         case CS_ERR_BAD_HANDLE: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case CS_ERR_BUSY: | ||||
| 		errno = EBUSY; | ||||
| 		break; | ||||
|         case CS_ERR_ACCESS: | ||||
| 		errno = EPERM; | ||||
| 		break; | ||||
|         case CS_ERR_NOT_EXIST: | ||||
| 		errno = ENOENT; | ||||
| 		break; | ||||
|         case CS_ERR_NAME_TOO_LONG: | ||||
| 		errno = ENAMETOOLONG; | ||||
| 		break; | ||||
|         case CS_ERR_EXIST: | ||||
| 		errno = EEXIST; | ||||
| 		break; | ||||
|         case CS_ERR_NO_SPACE: | ||||
| 		errno = ENOSPC; | ||||
| 		break; | ||||
|         case CS_ERR_INTERRUPT: | ||||
| 		errno = EINTR; | ||||
| 		break; | ||||
| 	case CS_ERR_NAME_NOT_FOUND: | ||||
| 		errno = ENOENT; | ||||
| 		break; | ||||
|         case CS_ERR_NO_RESOURCES: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
|         case CS_ERR_NOT_SUPPORTED: | ||||
| 		errno = EOPNOTSUPP; | ||||
| 		break; | ||||
|         case CS_ERR_BAD_OPERATION: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case CS_ERR_FAILED_OPERATION: | ||||
| 		errno = EIO; | ||||
| 		break; | ||||
|         case CS_ERR_MESSAGE_ERROR: | ||||
| 		errno = EIO; | ||||
| 		break; | ||||
|         case CS_ERR_QUEUE_FULL: | ||||
| 		errno = EXFULL; | ||||
| 		break; | ||||
|         case CS_ERR_QUEUE_NOT_AVAILABLE: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case CS_ERR_BAD_FLAGS: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case CS_ERR_TOO_BIG: | ||||
| 		errno = E2BIG; | ||||
| 		break; | ||||
|         case CS_ERR_NO_SECTIONS: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
| 	default: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static char *print_corosync_csid(const char *csid) | ||||
| { | ||||
| 	static char buf[128]; | ||||
| 	int id; | ||||
|  | ||||
| 	memcpy(&id, csid, sizeof(int)); | ||||
| 	sprintf(buf, "%d", id); | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| static void corosync_cpg_deliver_callback (cpg_handle_t handle, | ||||
| 				  const struct cpg_name *groupName, | ||||
| 				  uint32_t nodeid, | ||||
| 				  uint32_t pid, | ||||
| 				  void *msg, | ||||
| 				  size_t msg_len) | ||||
| { | ||||
| 	int target_nodeid; | ||||
|  | ||||
| 	memcpy(&target_nodeid, msg, COROSYNC_CSID_LEN); | ||||
|  | ||||
| 	DEBUGLOG("%u got message from nodeid %d for %d. len %zd\n", | ||||
| 		 our_nodeid, nodeid, target_nodeid, msg_len-4); | ||||
|  | ||||
| 	if (nodeid != our_nodeid) | ||||
| 		if (target_nodeid == our_nodeid || target_nodeid == 0) | ||||
| 			process_message(cluster_client, (char *)msg+COROSYNC_CSID_LEN, | ||||
| 					msg_len-COROSYNC_CSID_LEN, (char*)&nodeid); | ||||
| } | ||||
|  | ||||
| static void corosync_cpg_confchg_callback(cpg_handle_t handle, | ||||
| 				 const struct cpg_name *groupName, | ||||
| 				 const struct cpg_address *member_list, size_t member_list_entries, | ||||
| 				 const struct cpg_address *left_list, size_t left_list_entries, | ||||
| 				 const struct cpg_address *joined_list, size_t joined_list_entries) | ||||
| { | ||||
| 	int i; | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	DEBUGLOG("confchg callback. %zd joined, %zd left, %zd members\n", | ||||
| 		 joined_list_entries, left_list_entries, member_list_entries); | ||||
|  | ||||
| 	for (i=0; i<joined_list_entries; i++) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, | ||||
| 					      (char *)&joined_list[i].nodeid, | ||||
| 					      COROSYNC_CSID_LEN); | ||||
| 		if (!ninfo) { | ||||
| 			ninfo = malloc(sizeof(struct node_info)); | ||||
| 			if (!ninfo) { | ||||
| 				break; | ||||
| 			} | ||||
| 			else { | ||||
| 				ninfo->nodeid = joined_list[i].nodeid; | ||||
| 				dm_hash_insert_binary(node_hash, | ||||
| 						      (char *)&ninfo->nodeid, | ||||
| 						      COROSYNC_CSID_LEN, ninfo); | ||||
| 			} | ||||
| 		} | ||||
| 		ninfo->state = NODE_CLVMD; | ||||
| 	} | ||||
|  | ||||
| 	for (i=0; i<left_list_entries; i++) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, | ||||
| 					      (char *)&left_list[i].nodeid, | ||||
| 					      COROSYNC_CSID_LEN); | ||||
| 		if (ninfo) | ||||
| 			ninfo->state = NODE_DOWN; | ||||
| 	} | ||||
|  | ||||
| 	num_nodes = member_list_entries; | ||||
| } | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	cs_error_t err; | ||||
|  | ||||
| #ifdef QUORUM_SET	/* corosync/quorum.h */ | ||||
| 	uint32_t quorum_type; | ||||
| #endif | ||||
|  | ||||
| 	node_hash = dm_hash_create(100); | ||||
|  | ||||
| 	err = cpg_initialize(&cpg_handle, | ||||
| 			     &corosync_cpg_callbacks); | ||||
| 	if (err != CS_OK) { | ||||
| 		syslog(LOG_ERR, "Cannot initialise Corosync CPG service: %d", | ||||
| 		       err); | ||||
| 		DEBUGLOG("Cannot initialise Corosync CPG service: %d", err); | ||||
| 		return cs_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| #ifdef QUORUM_SET | ||||
| 	err = quorum_initialize(&quorum_handle, | ||||
| 				&quorum_callbacks, | ||||
| 				&quorum_type); | ||||
|  | ||||
| 	if (quorum_type != QUORUM_SET) { | ||||
| 		syslog(LOG_ERR, "Corosync quorum service is not configured"); | ||||
| 		DEBUGLOG("Corosync quorum service is not configured"); | ||||
| 		return EINVAL; | ||||
| 	} | ||||
| #else | ||||
| 	err = quorum_initialize(&quorum_handle, | ||||
| 				&quorum_callbacks); | ||||
| #endif | ||||
|  | ||||
| 	if (err != CS_OK) { | ||||
| 		syslog(LOG_ERR, "Cannot initialise Corosync quorum service: %d", | ||||
| 		       err); | ||||
| 		DEBUGLOG("Cannot initialise Corosync quorum service: %d", err); | ||||
| 		return cs_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	/* Create a lockspace for LV & VG locks to live in */ | ||||
| 	lockspace = dlm_open_lockspace(LOCKSPACE_NAME); | ||||
| 	if (!lockspace) { | ||||
| 		lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600); | ||||
| 		if (!lockspace) { | ||||
| 			syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		DEBUGLOG("Created DLM lockspace for CLVMD.\n"); | ||||
| 	} else | ||||
| 		DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n"); | ||||
|  | ||||
| 	dlm_ls_pthread_init(lockspace); | ||||
| 	DEBUGLOG("DLM initialisation complete\n"); | ||||
|  | ||||
| 	/* Connect to the clvmd group */ | ||||
| 	strcpy((char *)cpg_group_name.value, "clvmd"); | ||||
| 	cpg_group_name.length = strlen((char *)cpg_group_name.value); | ||||
| 	err = cpg_join(cpg_handle, &cpg_group_name); | ||||
| 	if (err != CS_OK) { | ||||
| 		cpg_finalize(cpg_handle); | ||||
| 		quorum_finalize(quorum_handle); | ||||
| 		dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); | ||||
| 		syslog(LOG_ERR, "Cannot join clvmd process group"); | ||||
| 		DEBUGLOG("Cannot join clvmd process group: %d\n", err); | ||||
| 		return cs_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	err = cpg_local_get(cpg_handle, | ||||
| 			    &our_nodeid); | ||||
| 	if (err != CS_OK) { | ||||
| 		cpg_finalize(cpg_handle); | ||||
| 		quorum_finalize(quorum_handle); | ||||
| 		dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); | ||||
| 		syslog(LOG_ERR, "Cannot get local node id\n"); | ||||
| 		return cs_to_errno(err); | ||||
| 	} | ||||
| 	DEBUGLOG("Our local node id is %d\n", our_nodeid); | ||||
|  | ||||
| 	DEBUGLOG("Connected to Corosync\n"); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown(void) | ||||
| { | ||||
| 	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1); | ||||
| 	cpg_finalize(cpg_handle); | ||||
| 	quorum_finalize(quorum_handle); | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	memcpy(csid, &our_nodeid, sizeof(int)); | ||||
| } | ||||
|  | ||||
| /* Corosync doesn't really have nmode names so we | ||||
|    just use the node ID in hex instead */ | ||||
| static int _csid_from_name(char *csid, const char *name) | ||||
| { | ||||
| 	int nodeid; | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	if (sscanf(name, "%x", &nodeid) == 1) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN); | ||||
| 		if (ninfo) | ||||
| 			return nodeid; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int _name_from_csid(const char *csid, char *name) | ||||
| { | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN); | ||||
| 	if (!ninfo) | ||||
| 	{ | ||||
| 		sprintf(name, "UNKNOWN %s", print_corosync_csid(csid)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	sprintf(name, "%x", ninfo->nodeid); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes(void) | ||||
| { | ||||
| 	DEBUGLOG("num_nodes = %d\n", num_nodes); | ||||
| 	return num_nodes; | ||||
| } | ||||
|  | ||||
| /* Node is now known to be running a clvmd */ | ||||
| static void _add_up_node(const char *csid) | ||||
| { | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN); | ||||
| 	if (!ninfo) { | ||||
| 		DEBUGLOG("corosync_add_up_node no node_hash entry for csid %s\n", | ||||
| 			 print_corosync_csid(csid)); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("corosync_add_up_node %d\n", ninfo->nodeid); | ||||
|  | ||||
| 	ninfo->state = NODE_CLVMD; | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| /* Call a callback for each node, so the caller knows whether it's up or down */ | ||||
| static int _cluster_do_node_callback(struct local_client *master_client, | ||||
| 				     void (*callback)(struct local_client *, | ||||
| 						      const char *csid, int node_up)) | ||||
| { | ||||
| 	struct dm_hash_node *hn; | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	dm_hash_iterate(hn, node_hash) | ||||
| 	{ | ||||
| 		char csid[COROSYNC_CSID_LEN]; | ||||
|  | ||||
| 		ninfo = dm_hash_get_data(node_hash, hn); | ||||
| 		memcpy(csid, dm_hash_get_key(node_hash, hn), COROSYNC_CSID_LEN); | ||||
|  | ||||
| 		DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid, | ||||
| 			 ninfo->state); | ||||
|  | ||||
| 		if (ninfo->state == NODE_CLVMD) | ||||
| 			callback(master_client, csid, 1); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Real locking */ | ||||
| static int _lock_resource(const char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	struct dlm_lksb lksb; | ||||
| 	int err; | ||||
|  | ||||
| 	DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode); | ||||
|  | ||||
| 	if (flags & LKF_CONVERT) | ||||
| 		lksb.sb_lkid = *lockid; | ||||
|  | ||||
| 	err = dlm_ls_lock_wait(lockspace, | ||||
| 			       mode, | ||||
| 			       &lksb, | ||||
| 			       flags, | ||||
| 			       resource, | ||||
| 			       strlen(resource), | ||||
| 			       0, | ||||
| 			       NULL, NULL, NULL); | ||||
|  | ||||
| 	if (err != 0) | ||||
| 	{ | ||||
| 		DEBUGLOG("dlm_ls_lock returned %d\n", errno); | ||||
| 		return err; | ||||
| 	} | ||||
| 	if (lksb.sb_status != 0) | ||||
| 	{ | ||||
| 		DEBUGLOG("dlm_ls_lock returns lksb.sb_status %d\n", lksb.sb_status); | ||||
| 		errno = lksb.sb_status; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("lock_resource returning %d, lock_id=%x\n", err, lksb.sb_lkid); | ||||
|  | ||||
| 	*lockid = lksb.sb_lkid; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int _unlock_resource(const char *resource, int lockid) | ||||
| { | ||||
| 	struct dlm_lksb lksb; | ||||
| 	int err; | ||||
|  | ||||
| 	DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid); | ||||
| 	lksb.sb_lkid = lockid; | ||||
|  | ||||
| 	err = dlm_ls_unlock_wait(lockspace, | ||||
| 				 lockid, | ||||
| 				 0, | ||||
| 				 &lksb); | ||||
| 	if (err != 0) | ||||
| 	{ | ||||
| 		DEBUGLOG("Unlock returned %d\n", err); | ||||
| 		return err; | ||||
| 	} | ||||
| 	if (lksb.sb_status != EUNLOCK) | ||||
| 	{ | ||||
| 		DEBUGLOG("dlm_ls_unlock_wait returns lksb.sb_status: %d\n", lksb.sb_status); | ||||
| 		errno = lksb.sb_status; | ||||
| 		return -1; | ||||
| 	}    | ||||
|  | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _is_quorate(void) | ||||
| { | ||||
| 	int quorate; | ||||
| 	if (quorum_getquorate(quorum_handle, &quorate) == CS_OK) | ||||
| 		return quorate; | ||||
| 	else | ||||
| 		return 0; | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd(void) | ||||
| { | ||||
| 	int select_fd; | ||||
|  | ||||
| 	cpg_fd_get(cpg_handle, &select_fd); | ||||
| 	return select_fd; | ||||
| } | ||||
|  | ||||
| static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, | ||||
| 				const char *csid, | ||||
| 				struct local_client **new_client) | ||||
| { | ||||
| 	cluster_client = fd; | ||||
| 	*new_client = NULL; | ||||
| 	cpg_dispatch(cpg_handle, CS_DISPATCH_ONE); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _cluster_send_message(const void *buf, int msglen, const char *csid, | ||||
| 				 const char *errtext) | ||||
| { | ||||
| 	struct iovec iov[2]; | ||||
| 	cs_error_t err; | ||||
| 	int target_node; | ||||
|  | ||||
| 	if (csid) | ||||
| 		memcpy(&target_node, csid, COROSYNC_CSID_LEN); | ||||
| 	else | ||||
| 		target_node = 0; | ||||
|  | ||||
| 	iov[0].iov_base = &target_node; | ||||
| 	iov[0].iov_len = sizeof(int); | ||||
| 	iov[1].iov_base = (char *)buf; | ||||
| 	iov[1].iov_len = msglen; | ||||
|  | ||||
| 	err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2); | ||||
| 	return cs_to_errno(err); | ||||
| } | ||||
|  | ||||
| #ifdef HAVE_COROSYNC_CONFDB_H | ||||
| /* | ||||
|  * We are not necessarily connected to a Red Hat Cluster system, | ||||
|  * but if we are, this returns the cluster name from cluster.conf. | ||||
|  * I've used confdb rather than ccs to reduce the inter-package | ||||
|  * dependancies as well as to allow people to set a cluster name | ||||
|  * for themselves even if they are not running on RH cluster. | ||||
|  */ | ||||
| static int _get_cluster_name(char *buf, int buflen) | ||||
| { | ||||
| 	confdb_handle_t handle; | ||||
| 	int result; | ||||
| 	size_t namelen = buflen; | ||||
| 	hdb_handle_t cluster_handle; | ||||
| 	confdb_callbacks_t callbacks = { | ||||
| 		.confdb_key_change_notify_fn = NULL, | ||||
| 		.confdb_object_create_change_notify_fn = NULL, | ||||
| 		.confdb_object_delete_change_notify_fn = NULL | ||||
| 	}; | ||||
|  | ||||
| 	/* This is a default in case everything else fails */ | ||||
| 	strncpy(buf, "Corosync", buflen); | ||||
|  | ||||
| 	/* Look for a cluster name in confdb */ | ||||
| 	result = confdb_initialize (&handle, &callbacks); | ||||
|         if (result != CS_OK) | ||||
| 		return 0; | ||||
|  | ||||
|         result = confdb_object_find_start(handle, OBJECT_PARENT_HANDLE); | ||||
| 	if (result != CS_OK) | ||||
| 		goto out; | ||||
|  | ||||
|         result = confdb_object_find(handle, OBJECT_PARENT_HANDLE, (void *)"cluster", strlen("cluster"), &cluster_handle); | ||||
|         if (result != CS_OK) | ||||
| 		goto out; | ||||
|  | ||||
|         result = confdb_key_get(handle, cluster_handle, (void *)"name", strlen("name"), buf, &namelen); | ||||
|         if (result != CS_OK) | ||||
| 		goto out; | ||||
|  | ||||
| 	buf[namelen] = '\0'; | ||||
|  | ||||
| out: | ||||
| 	confdb_finalize(handle); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #elif defined HAVE_COROSYNC_CMAP_H | ||||
|  | ||||
| static int _get_cluster_name(char *buf, int buflen) | ||||
| { | ||||
| 	cmap_handle_t cmap_handle = 0; | ||||
| 	int result; | ||||
| 	char *name = NULL; | ||||
|  | ||||
| 	/* This is a default in case everything else fails */ | ||||
| 	strncpy(buf, "Corosync", buflen); | ||||
|  | ||||
| 	/* Look for a cluster name in cmap */ | ||||
| 	result = cmap_initialize(&cmap_handle); | ||||
| 	if (result != CS_OK) | ||||
| 		return 0; | ||||
|  | ||||
| 	result = cmap_get_string(cmap_handle, "totem.cluster_name", &name); | ||||
| 	if (result != CS_OK) | ||||
| 		goto out; | ||||
|  | ||||
| 	memset(buf, 0, buflen); | ||||
| 	strncpy(buf, name, buflen - 1); | ||||
|  | ||||
| out: | ||||
| 	if (name) | ||||
| 		free(name); | ||||
| 	cmap_finalize(cmap_handle); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| static struct cluster_ops _cluster_corosync_ops = { | ||||
| 	.name                     = "corosync", | ||||
| 	.cluster_init_completed   = NULL, | ||||
| 	.cluster_send_message     = _cluster_send_message, | ||||
| 	.name_from_csid           = _name_from_csid, | ||||
| 	.csid_from_name           = _csid_from_name, | ||||
| 	.get_num_nodes            = _get_num_nodes, | ||||
| 	.cluster_fd_callback      = _cluster_fd_callback, | ||||
| 	.get_main_cluster_fd      = _get_main_cluster_fd, | ||||
| 	.cluster_do_node_callback = _cluster_do_node_callback, | ||||
| 	.is_quorate               = _is_quorate, | ||||
| 	.get_our_csid             = _get_our_csid, | ||||
| 	.add_up_node              = _add_up_node, | ||||
| 	.reread_config            = NULL, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.get_cluster_name         = _get_cluster_name, | ||||
| 	.sync_lock                = _lock_resource, | ||||
| 	.sync_unlock              = _unlock_resource, | ||||
| }; | ||||
|  | ||||
| struct cluster_ops *init_corosync_cluster(void) | ||||
| { | ||||
| 	if (!_init_cluster()) | ||||
| 		return &_cluster_corosync_ops; | ||||
| 	else | ||||
| 		return NULL; | ||||
| } | ||||
| @@ -1,689 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This provides the interface between clvmd and OpenAIS as the cluster | ||||
|  * and lock manager. | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
| #include <fcntl.h> | ||||
| #include <syslog.h> | ||||
|  | ||||
| #include <openais/saAis.h> | ||||
| #include <openais/saLck.h> | ||||
|  | ||||
| #include <corosync/corotypes.h> | ||||
| #include <corosync/cpg.h> | ||||
|  | ||||
| #include "locking.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "lvm-functions.h" | ||||
| #include "clvmd.h" | ||||
|  | ||||
| /* Timeout value for several openais calls */ | ||||
| #define TIMEOUT 10 | ||||
|  | ||||
| static void openais_cpg_deliver_callback (cpg_handle_t handle, | ||||
| 				  const struct cpg_name *groupName, | ||||
| 				  uint32_t nodeid, | ||||
| 				  uint32_t pid, | ||||
| 				  void *msg, | ||||
| 				  size_t msg_len); | ||||
| static void openais_cpg_confchg_callback(cpg_handle_t handle, | ||||
| 				 const struct cpg_name *groupName, | ||||
| 				 const struct cpg_address *member_list, size_t member_list_entries, | ||||
| 				 const struct cpg_address *left_list, size_t left_list_entries, | ||||
| 				 const struct cpg_address *joined_list, size_t joined_list_entries); | ||||
|  | ||||
| static void _cluster_closedown(void); | ||||
|  | ||||
| /* Hash list of nodes in the cluster */ | ||||
| static struct dm_hash_table *node_hash; | ||||
|  | ||||
| /* For associating lock IDs & resource handles */ | ||||
| static struct dm_hash_table *lock_hash; | ||||
|  | ||||
| /* Number of active nodes */ | ||||
| static int num_nodes; | ||||
| static unsigned int our_nodeid; | ||||
|  | ||||
| static struct local_client *cluster_client; | ||||
|  | ||||
| /* OpenAIS handles */ | ||||
| static cpg_handle_t cpg_handle; | ||||
| static SaLckHandleT lck_handle; | ||||
|  | ||||
| static struct cpg_name cpg_group_name; | ||||
|  | ||||
| /* Openais callback structs */ | ||||
| cpg_callbacks_t openais_cpg_callbacks = { | ||||
| 	.cpg_deliver_fn =            openais_cpg_deliver_callback, | ||||
| 	.cpg_confchg_fn =            openais_cpg_confchg_callback, | ||||
| }; | ||||
|  | ||||
| struct node_info | ||||
| { | ||||
| 	enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state; | ||||
| 	int nodeid; | ||||
| }; | ||||
|  | ||||
| struct lock_info | ||||
| { | ||||
| 	SaLckResourceHandleT res_handle; | ||||
| 	SaLckLockIdT         lock_id; | ||||
| 	SaNameT              lock_name; | ||||
| }; | ||||
|  | ||||
| /* Set errno to something approximating the right value and return 0 or -1 */ | ||||
| static int ais_to_errno(SaAisErrorT err) | ||||
| { | ||||
| 	switch(err) | ||||
| 	{ | ||||
| 	case SA_AIS_OK: | ||||
| 		return 0; | ||||
|         case SA_AIS_ERR_LIBRARY: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_VERSION: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_INIT: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_TIMEOUT: | ||||
| 		errno = ETIME; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_TRY_AGAIN: | ||||
| 		errno = EAGAIN; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_INVALID_PARAM: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NO_MEMORY: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_BAD_HANDLE: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_BUSY: | ||||
| 		errno = EBUSY; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_ACCESS: | ||||
| 		errno = EPERM; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NOT_EXIST: | ||||
| 		errno = ENOENT; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NAME_TOO_LONG: | ||||
| 		errno = ENAMETOOLONG; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_EXIST: | ||||
| 		errno = EEXIST; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NO_SPACE: | ||||
| 		errno = ENOSPC; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_INTERRUPT: | ||||
| 		errno = EINTR; | ||||
| 		break; | ||||
| 	case SA_AIS_ERR_NAME_NOT_FOUND: | ||||
| 		errno = ENOENT; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NO_RESOURCES: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NOT_SUPPORTED: | ||||
| 		errno = EOPNOTSUPP; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_BAD_OPERATION: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_FAILED_OPERATION: | ||||
| 		errno = EIO; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_MESSAGE_ERROR: | ||||
| 		errno = EIO; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_QUEUE_FULL: | ||||
| 		errno = EXFULL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_QUEUE_NOT_AVAILABLE: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_BAD_FLAGS: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_TOO_BIG: | ||||
| 		errno = E2BIG; | ||||
| 		break; | ||||
|         case SA_AIS_ERR_NO_SECTIONS: | ||||
| 		errno = ENOMEM; | ||||
| 		break; | ||||
| 	default: | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static char *print_openais_csid(const char *csid) | ||||
| { | ||||
| 	static char buf[128]; | ||||
| 	int id; | ||||
|  | ||||
| 	memcpy(&id, csid, sizeof(int)); | ||||
| 	sprintf(buf, "%d", id); | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| static int add_internal_client(int fd, fd_callback_t callback) | ||||
| { | ||||
| 	struct local_client *client; | ||||
|  | ||||
| 	DEBUGLOG("Add_internal_client, fd = %d\n", fd); | ||||
|  | ||||
| 	if (!(client = dm_zalloc(sizeof(*client)))) { | ||||
| 		DEBUGLOG("malloc failed\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	client->fd = fd; | ||||
| 	client->type = CLUSTER_INTERNAL; | ||||
| 	client->callback = callback; | ||||
| 	add_client(client); | ||||
|  | ||||
| 	/* Set Close-on-exec */ | ||||
| 	fcntl(fd, F_SETFD, 1); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void openais_cpg_deliver_callback (cpg_handle_t handle, | ||||
| 				  const struct cpg_name *groupName, | ||||
| 				  uint32_t nodeid, | ||||
| 				  uint32_t pid, | ||||
| 				  void *msg, | ||||
| 				  size_t msg_len) | ||||
| { | ||||
| 	int target_nodeid; | ||||
|  | ||||
| 	memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN); | ||||
|  | ||||
| 	DEBUGLOG("%u got message from nodeid %d for %d. len %" PRIsize_t "\n", | ||||
| 		 our_nodeid, nodeid, target_nodeid, msg_len-4); | ||||
|  | ||||
| 	if (nodeid != our_nodeid) | ||||
| 		if (target_nodeid == our_nodeid || target_nodeid == 0) | ||||
| 			process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN, | ||||
| 					msg_len-OPENAIS_CSID_LEN, (char*)&nodeid); | ||||
| } | ||||
|  | ||||
| static void openais_cpg_confchg_callback(cpg_handle_t handle, | ||||
| 				 const struct cpg_name *groupName, | ||||
| 				 const struct cpg_address *member_list, size_t member_list_entries, | ||||
| 				 const struct cpg_address *left_list, size_t left_list_entries, | ||||
| 				 const struct cpg_address *joined_list, size_t joined_list_entries) | ||||
| { | ||||
| 	int i; | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	DEBUGLOG("confchg callback. %" PRIsize_t " joined, " | ||||
| 		 "%" PRIsize_t " left, %" PRIsize_t " members\n", | ||||
| 		 joined_list_entries, left_list_entries, member_list_entries); | ||||
|  | ||||
| 	for (i=0; i<joined_list_entries; i++) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, | ||||
| 					      (char *)&joined_list[i].nodeid, | ||||
| 					      OPENAIS_CSID_LEN); | ||||
| 		if (!ninfo) { | ||||
| 			ninfo = malloc(sizeof(struct node_info)); | ||||
| 			if (!ninfo) { | ||||
| 				break; | ||||
| 			} | ||||
| 			else { | ||||
| 				ninfo->nodeid = joined_list[i].nodeid; | ||||
| 				dm_hash_insert_binary(node_hash, | ||||
| 						      (char *)&ninfo->nodeid, | ||||
| 						      OPENAIS_CSID_LEN, ninfo); | ||||
| 			} | ||||
| 		} | ||||
| 		ninfo->state = NODE_CLVMD; | ||||
| 	} | ||||
|  | ||||
| 	for (i=0; i<left_list_entries; i++) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, | ||||
| 					      (char *)&left_list[i].nodeid, | ||||
| 					      OPENAIS_CSID_LEN); | ||||
| 		if (ninfo) | ||||
| 			ninfo->state = NODE_DOWN; | ||||
| 	} | ||||
|  | ||||
| 	for (i=0; i<member_list_entries; i++) { | ||||
| 		if (member_list[i].nodeid == 0) continue; | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, | ||||
| 				(char *)&member_list[i].nodeid, | ||||
| 				OPENAIS_CSID_LEN); | ||||
| 		if (!ninfo) { | ||||
| 			ninfo = malloc(sizeof(struct node_info)); | ||||
| 			if (!ninfo) { | ||||
| 				break; | ||||
| 			} | ||||
| 			else { | ||||
| 				ninfo->nodeid = member_list[i].nodeid; | ||||
| 				dm_hash_insert_binary(node_hash, | ||||
| 						(char *)&ninfo->nodeid, | ||||
| 						OPENAIS_CSID_LEN, ninfo); | ||||
| 			} | ||||
| 		} | ||||
| 		ninfo->state = NODE_CLVMD; | ||||
| 	} | ||||
|  | ||||
| 	num_nodes = member_list_entries; | ||||
| } | ||||
|  | ||||
| static int lck_dispatch(struct local_client *client, char *buf, int len, | ||||
| 			const char *csid, struct local_client **new_client) | ||||
| { | ||||
| 	*new_client = NULL; | ||||
| 	saLckDispatch(lck_handle, SA_DISPATCH_ONE); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	SaAisErrorT err; | ||||
| 	SaVersionT  ver = { 'B', 1, 1 }; | ||||
| 	int select_fd; | ||||
|  | ||||
| 	node_hash = dm_hash_create(100); | ||||
| 	lock_hash = dm_hash_create(10); | ||||
|  | ||||
| 	err = cpg_initialize(&cpg_handle, | ||||
| 			     &openais_cpg_callbacks); | ||||
| 	if (err != SA_AIS_OK) { | ||||
| 		syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d", | ||||
| 		       err); | ||||
| 		DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	err = saLckInitialize(&lck_handle, | ||||
| 					NULL, | ||||
| 			      &ver); | ||||
| 	if (err != SA_AIS_OK) { | ||||
| 		cpg_initialize(&cpg_handle, &openais_cpg_callbacks); | ||||
| 		syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d", | ||||
| 		       err); | ||||
| 		DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	/* Connect to the clvmd group */ | ||||
| 	strcpy((char *)cpg_group_name.value, "clvmd"); | ||||
| 	cpg_group_name.length = strlen((char *)cpg_group_name.value); | ||||
| 	err = cpg_join(cpg_handle, &cpg_group_name); | ||||
| 	if (err != SA_AIS_OK) { | ||||
| 		cpg_finalize(cpg_handle); | ||||
| 		saLckFinalize(lck_handle); | ||||
| 		syslog(LOG_ERR, "Cannot join clvmd process group"); | ||||
| 		DEBUGLOG("Cannot join clvmd process group: %d\n", err); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	err = cpg_local_get(cpg_handle, | ||||
| 			    &our_nodeid); | ||||
| 	if (err != SA_AIS_OK) { | ||||
| 		cpg_finalize(cpg_handle); | ||||
| 		saLckFinalize(lck_handle); | ||||
| 		syslog(LOG_ERR, "Cannot get local node id\n"); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
| 	DEBUGLOG("Our local node id is %d\n", our_nodeid); | ||||
|  | ||||
| 	saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd); | ||||
| 	add_internal_client(select_fd, lck_dispatch); | ||||
|  | ||||
| 	DEBUGLOG("Connected to OpenAIS\n"); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown(void) | ||||
| { | ||||
| 	saLckFinalize(lck_handle); | ||||
| 	cpg_finalize(cpg_handle); | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	memcpy(csid, &our_nodeid, sizeof(int)); | ||||
| } | ||||
|  | ||||
| /* OpenAIS doesn't really have nmode names so we | ||||
|    just use the node ID in hex instead */ | ||||
| static int _csid_from_name(char *csid, const char *name) | ||||
| { | ||||
| 	int nodeid; | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	if (sscanf(name, "%x", &nodeid) == 1) { | ||||
| 		ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN); | ||||
| 		if (ninfo) | ||||
| 			return nodeid; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int _name_from_csid(const char *csid, char *name) | ||||
| { | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN); | ||||
| 	if (!ninfo) | ||||
| 	{ | ||||
| 		sprintf(name, "UNKNOWN %s", print_openais_csid(csid)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	sprintf(name, "%x", ninfo->nodeid); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes() | ||||
| { | ||||
| 	DEBUGLOG("num_nodes = %d\n", num_nodes); | ||||
| 	return num_nodes; | ||||
| } | ||||
|  | ||||
| /* Node is now known to be running a clvmd */ | ||||
| static void _add_up_node(const char *csid) | ||||
| { | ||||
| 	struct node_info *ninfo; | ||||
|  | ||||
| 	ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN); | ||||
| 	if (!ninfo) { | ||||
| 		DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n", | ||||
| 			 print_openais_csid(csid)); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid); | ||||
|  | ||||
| 	ninfo->state = NODE_CLVMD; | ||||
|  | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| /* Call a callback for each node, so the caller knows whether it's up or down */ | ||||
| static int _cluster_do_node_callback(struct local_client *master_client, | ||||
| 				     void (*callback)(struct local_client *, | ||||
| 						      const char *csid, int node_up)) | ||||
| { | ||||
| 	struct dm_hash_node *hn; | ||||
| 	struct node_info *ninfo; | ||||
| 	int somedown = 0; | ||||
|  | ||||
| 	dm_hash_iterate(hn, node_hash) | ||||
| 	{ | ||||
| 		char csid[OPENAIS_CSID_LEN]; | ||||
|  | ||||
| 		ninfo = dm_hash_get_data(node_hash, hn); | ||||
| 		memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN); | ||||
|  | ||||
| 		DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid, | ||||
| 			 ninfo->state); | ||||
|  | ||||
| 		if (ninfo->state != NODE_DOWN) | ||||
| 			callback(master_client, csid, ninfo->state == NODE_CLVMD); | ||||
| 		if (ninfo->state != NODE_CLVMD) | ||||
| 			somedown = -1; | ||||
| 	} | ||||
| 	return somedown; | ||||
| } | ||||
|  | ||||
| /* Real locking */ | ||||
| static int _lock_resource(char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	struct lock_info *linfo; | ||||
| 	SaLckResourceHandleT res_handle; | ||||
| 	SaAisErrorT err; | ||||
| 	SaLckLockIdT lock_id; | ||||
| 	SaLckLockStatusT lockStatus; | ||||
|  | ||||
| 	/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */ | ||||
| 	if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE; | ||||
|  | ||||
| 	linfo = malloc(sizeof(struct lock_info)); | ||||
| 	if (!linfo) | ||||
| 		return -1; | ||||
|  | ||||
| 	DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode); | ||||
|  | ||||
| 	linfo->lock_name.length = strlen(resource)+1; | ||||
| 	strcpy((char *)linfo->lock_name.value, resource); | ||||
|  | ||||
| 	err = saLckResourceOpen(lck_handle, &linfo->lock_name, | ||||
| 				SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle); | ||||
| 	if (err != SA_AIS_OK) | ||||
| 	{ | ||||
| 		DEBUGLOG("ResourceOpen returned %d\n", err); | ||||
| 		free(linfo); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	err = saLckResourceLock( | ||||
| 			res_handle, | ||||
| 			&lock_id, | ||||
| 			mode, | ||||
| 			flags, | ||||
| 			0, | ||||
| 			SA_TIME_END, | ||||
| 			&lockStatus); | ||||
| 	if (err != SA_AIS_OK && lockStatus != SA_LCK_LOCK_GRANTED) | ||||
| 	{ | ||||
| 		free(linfo); | ||||
| 		saLckResourceClose(res_handle); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	/* Wait for it to complete */ | ||||
|  | ||||
| 	DEBUGLOG("lock_resource returning %d, lock_id=%" PRIx64 "\n", | ||||
| 		 err, lock_id); | ||||
|  | ||||
| 	linfo->lock_id = lock_id; | ||||
| 	linfo->res_handle = res_handle; | ||||
|  | ||||
| 	dm_hash_insert(lock_hash, resource, linfo); | ||||
|  | ||||
| 	return ais_to_errno(err); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int _unlock_resource(char *resource, int lockid) | ||||
| { | ||||
| 	SaAisErrorT err; | ||||
| 	struct lock_info *linfo; | ||||
|  | ||||
| 	DEBUGLOG("unlock_resource %s\n", resource); | ||||
| 	linfo = dm_hash_lookup(lock_hash, resource); | ||||
| 	if (!linfo) | ||||
| 		return 0; | ||||
|  | ||||
| 	DEBUGLOG("unlock_resource: lockid: %" PRIx64 "\n", linfo->lock_id); | ||||
| 	err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END); | ||||
| 	if (err != SA_AIS_OK) | ||||
| 	{ | ||||
| 		DEBUGLOG("Unlock returned %d\n", err); | ||||
| 		return ais_to_errno(err); | ||||
| 	} | ||||
|  | ||||
| 	/* Release the resource */ | ||||
| 	dm_hash_remove(lock_hash, resource); | ||||
| 	saLckResourceClose(linfo->res_handle); | ||||
| 	free(linfo); | ||||
|  | ||||
| 	return ais_to_errno(err); | ||||
| } | ||||
|  | ||||
| static int _sync_lock(const char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	int status; | ||||
| 	char lock1[strlen(resource)+3]; | ||||
| 	char lock2[strlen(resource)+3]; | ||||
|  | ||||
| 	snprintf(lock1, sizeof(lock1), "%s-1", resource); | ||||
| 	snprintf(lock2, sizeof(lock2), "%s-2", resource); | ||||
|  | ||||
| 	switch (mode) | ||||
| 	{ | ||||
| 	case LCK_EXCL: | ||||
| 		status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid); | ||||
| 		if (status) | ||||
| 			goto out; | ||||
|  | ||||
| 		/* If we can't get this lock too then bail out */ | ||||
| 		status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK, | ||||
| 					lockid); | ||||
| 		if (status == SA_LCK_LOCK_NOT_QUEUED) | ||||
| 		{ | ||||
| 			_unlock_resource(lock1, *lockid); | ||||
| 			status = -1; | ||||
| 			errno = EAGAIN; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_PREAD: | ||||
| 	case LCK_READ: | ||||
| 		status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid); | ||||
| 		if (status) | ||||
| 			goto out; | ||||
| 		_unlock_resource(lock2, *lockid); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_WRITE: | ||||
| 		status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid); | ||||
| 		if (status) | ||||
| 			goto out; | ||||
| 		_unlock_resource(lock1, *lockid); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		status = -1; | ||||
| 		errno = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
| out: | ||||
| 	*lockid = mode; | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| static int _sync_unlock(const char *resource, int lockid) | ||||
| { | ||||
| 	int status = 0; | ||||
| 	char lock1[strlen(resource)+3]; | ||||
| 	char lock2[strlen(resource)+3]; | ||||
|  | ||||
| 	snprintf(lock1, sizeof(lock1), "%s-1", resource); | ||||
| 	snprintf(lock2, sizeof(lock2), "%s-2", resource); | ||||
|  | ||||
| 	_unlock_resource(lock1, lockid); | ||||
| 	_unlock_resource(lock2, lockid); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* We are always quorate ! */ | ||||
| static int _is_quorate() | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd(void) | ||||
| { | ||||
| 	int select_fd; | ||||
|  | ||||
| 	cpg_fd_get(cpg_handle, &select_fd); | ||||
| 	return select_fd; | ||||
| } | ||||
|  | ||||
| static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, | ||||
| 				const char *csid, | ||||
| 				struct local_client **new_client) | ||||
| { | ||||
| 	cluster_client = fd; | ||||
| 	*new_client = NULL; | ||||
| 	cpg_dispatch(cpg_handle, SA_DISPATCH_ONE); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _cluster_send_message(const void *buf, int msglen, const char *csid, | ||||
| 				 const char *errtext) | ||||
| { | ||||
| 	struct iovec iov[2]; | ||||
| 	SaAisErrorT err; | ||||
| 	int target_node; | ||||
|  | ||||
| 	if (csid) | ||||
| 		memcpy(&target_node, csid, OPENAIS_CSID_LEN); | ||||
| 	else | ||||
| 		target_node = 0; | ||||
|  | ||||
| 	iov[0].iov_base = &target_node; | ||||
| 	iov[0].iov_len = sizeof(int); | ||||
| 	iov[1].iov_base = (char *)buf; | ||||
| 	iov[1].iov_len = msglen; | ||||
|  | ||||
| 	err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2); | ||||
| 	return ais_to_errno(err); | ||||
| } | ||||
|  | ||||
| /* We don't have a cluster name to report here */ | ||||
| static int _get_cluster_name(char *buf, int buflen) | ||||
| { | ||||
| 	strncpy(buf, "OpenAIS", buflen); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_openais_ops = { | ||||
| 	.name                     = "openais", | ||||
| 	.cluster_init_completed   = NULL, | ||||
| 	.cluster_send_message     = _cluster_send_message, | ||||
| 	.name_from_csid           = _name_from_csid, | ||||
| 	.csid_from_name           = _csid_from_name, | ||||
| 	.get_num_nodes            = _get_num_nodes, | ||||
| 	.cluster_fd_callback      = _cluster_fd_callback, | ||||
| 	.get_main_cluster_fd      = _get_main_cluster_fd, | ||||
| 	.cluster_do_node_callback = _cluster_do_node_callback, | ||||
| 	.is_quorate               = _is_quorate, | ||||
| 	.get_our_csid             = _get_our_csid, | ||||
| 	.add_up_node              = _add_up_node, | ||||
| 	.reread_config            = NULL, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.get_cluster_name         = _get_cluster_name, | ||||
| 	.sync_lock                = _sync_lock, | ||||
| 	.sync_unlock              = _sync_unlock, | ||||
| }; | ||||
|  | ||||
| struct cluster_ops *init_openais_cluster(void) | ||||
| { | ||||
| 	if (!_init_cluster()) | ||||
| 		return &_cluster_openais_ops; | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
| @@ -1,382 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2009-2013 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| #include "locking.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
|  | ||||
| #include <sys/un.h> | ||||
| #include <sys/socket.h> | ||||
| #include <fcntl.h> | ||||
|  | ||||
| static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock"; | ||||
| static int listen_fd = -1; | ||||
|  | ||||
| static struct dm_hash_table *_locks; | ||||
| static int _lockid; | ||||
|  | ||||
| static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
| /* Using one common condition for all locks for simplicity */ | ||||
| static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER; | ||||
|  | ||||
| struct lock { | ||||
| 	struct dm_list list; | ||||
| 	int lockid; | ||||
| 	int mode; | ||||
| }; | ||||
|  | ||||
| static void close_comms(void) | ||||
| { | ||||
| 	if (listen_fd != -1 && close(listen_fd)) | ||||
| 		stack; | ||||
| 	(void)unlink(SINGLENODE_CLVMD_SOCKNAME); | ||||
| 	listen_fd = -1; | ||||
| } | ||||
|  | ||||
| static int init_comms(void) | ||||
| { | ||||
| 	mode_t old_mask; | ||||
| 	struct sockaddr_un addr = { .sun_family = AF_UNIX }; | ||||
|  | ||||
| 	if (!dm_strncpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME, | ||||
| 			sizeof(addr.sun_path))) { | ||||
| 		DEBUGLOG("%s: singlenode socket name too long.", | ||||
| 			 SINGLENODE_CLVMD_SOCKNAME); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	close_comms(); | ||||
|  | ||||
| 	(void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK); | ||||
| 	old_mask = umask(0077); | ||||
|  | ||||
| 	listen_fd = socket(PF_UNIX, SOCK_STREAM, 0); | ||||
| 	if (listen_fd < 0) { | ||||
| 		DEBUGLOG("Can't create local socket: %s\n", strerror(errno)); | ||||
| 		goto error; | ||||
| 	} | ||||
| 	/* Set Close-on-exec */ | ||||
| 	if (fcntl(listen_fd, F_SETFD, 1)) { | ||||
| 		DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno)); | ||||
| 		goto error; | ||||
| 	} | ||||
|  | ||||
| 	if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { | ||||
| 		DEBUGLOG("Can't bind local socket: %s\n", strerror(errno)); | ||||
| 		goto error; | ||||
| 	} | ||||
| 	if (listen(listen_fd, 10) < 0) { | ||||
| 		DEBUGLOG("Can't listen local socket: %s\n", strerror(errno)); | ||||
| 		goto error; | ||||
| 	} | ||||
|  | ||||
| 	umask(old_mask); | ||||
| 	(void) dm_prepare_selinux_context(NULL, 0); | ||||
| 	return 0; | ||||
| error: | ||||
| 	umask(old_mask); | ||||
| 	(void) dm_prepare_selinux_context(NULL, 0); | ||||
| 	close_comms(); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	if (!(_locks = dm_hash_create(128))) { | ||||
| 		DEBUGLOG("Failed to allocate single-node hash table.\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	r = init_comms(); | ||||
| 	if (r) { | ||||
| 		dm_hash_destroy(_locks); | ||||
| 		_locks = NULL; | ||||
| 		return r; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("Single-node cluster initialised.\n"); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown(void) | ||||
| { | ||||
| 	close_comms(); | ||||
|  | ||||
| 	/* If there is any awaited resource, kill it softly */ | ||||
| 	pthread_mutex_lock(&_lock_mutex); | ||||
| 	dm_hash_destroy(_locks); | ||||
| 	_locks = NULL; | ||||
| 	_lockid = 0; | ||||
| 	pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */ | ||||
| 	pthread_mutex_unlock(&_lock_mutex); | ||||
| } | ||||
|  | ||||
| static void _get_our_csid(char *csid) | ||||
| { | ||||
| 	int nodeid = 1; | ||||
| 	memcpy(csid, &nodeid, sizeof(int)); | ||||
| } | ||||
|  | ||||
| static int _csid_from_name(char *csid, const char *name) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _name_from_csid(const char *csid, char *name) | ||||
| { | ||||
| 	strcpy(name, "SINGLENODE"); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes(void) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Node is now known to be running a clvmd */ | ||||
| static void _add_up_node(const char *csid) | ||||
| { | ||||
| } | ||||
|  | ||||
| /* Call a callback for each node, so the caller knows whether it's up or down */ | ||||
| static int _cluster_do_node_callback(struct local_client *master_client, | ||||
| 				     void (*callback)(struct local_client *, | ||||
| 				     const char *csid, int node_up)) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int _lock_file(const char *file, uint32_t flags); | ||||
|  | ||||
| static const char *_get_mode(int mode) | ||||
| { | ||||
| 	switch (mode) { | ||||
| 	case LCK_NULL: return "NULL"; | ||||
| 	case LCK_READ: return "READ"; | ||||
| 	case LCK_PREAD: return "PREAD"; | ||||
| 	case LCK_WRITE: return "WRITE"; | ||||
| 	case LCK_EXCL: return "EXCLUSIVE"; | ||||
| 	case LCK_UNLOCK: return "UNLOCK"; | ||||
| 	default: return "????"; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Real locking */ | ||||
| static int _lock_resource(const char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	/* DLM table of allowed transition states */ | ||||
| 	static const int _dlm_table[6][6] = { | ||||
| 	/* Mode	   NL	CR	CW	PR	PW	EX */ | ||||
| 	/* NL */ { 1,	 1,	 1,	 1,	 1,	 1}, | ||||
| 	/* CR */ { 1,	 1,	 1,	 1,	 1,	 0}, | ||||
| 	/* CW */ { 1,	 1,	 1,	 0,	 0,	 0}, | ||||
| 	/* PR */ { 1,	 1,	 0,	 1,	 0,	 0}, | ||||
| 	/* PW */ { 1,	 1,	 0,	 0,	 0,	 0}, | ||||
| 	/* EX */ { 1,	 0,	 0,	 0,	 0,	 0} | ||||
| 	}; | ||||
|  | ||||
| 	struct lock *lck = NULL, *lckt; | ||||
| 	struct dm_list *head; | ||||
|  | ||||
| 	DEBUGLOG("Locking resource %s, flags=0x%02x (%s%s%s), mode=%s (%d)\n", | ||||
| 		 resource, flags, | ||||
| 		 (flags & LCKF_NOQUEUE) ? "NOQUEUE" : "", | ||||
| 		 ((flags & (LCKF_NOQUEUE | LCKF_CONVERT)) == | ||||
| 		  (LCKF_NOQUEUE | LCKF_CONVERT)) ? "|" : "", | ||||
| 		 (flags & LCKF_CONVERT) ? "CONVERT" : "", | ||||
| 		 _get_mode(mode), mode); | ||||
|  | ||||
| 	mode &= LCK_TYPE_MASK; | ||||
| 	pthread_mutex_lock(&_lock_mutex); | ||||
|  | ||||
| retry: | ||||
| 	pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */ | ||||
|  | ||||
| 	if (!(head = dm_hash_lookup(_locks, resource))) { | ||||
| 		if (flags & LCKF_CONVERT) { | ||||
| 			/* In real DLM, lock is identified only by lockid, resource is not used */ | ||||
| 			DEBUGLOG("Unlocked resource %s cannot be converted\n", resource); | ||||
| 			goto_bad; | ||||
| 		} | ||||
| 		/* Add new locked resource */ | ||||
| 		if (!(head = dm_malloc(sizeof(struct dm_list))) || | ||||
| 		    !dm_hash_insert(_locks, resource, head)) { | ||||
| 			dm_free(head); | ||||
| 			goto_bad; | ||||
| 		} | ||||
|  | ||||
| 		dm_list_init(head); | ||||
| 	} else	/* Update/convert locked resource */ | ||||
| 		dm_list_iterate_items(lck, head) { | ||||
| 			/* Check is all locks are compatible with requested lock */ | ||||
| 			if (flags & LCKF_CONVERT) { | ||||
| 				if (lck->lockid != *lockid) | ||||
| 					continue; | ||||
|  | ||||
| 				DEBUGLOG("Converting resource %s lockid=%d mode:%s -> %s...\n", | ||||
| 					 resource, lck->lockid, _get_mode(lck->mode), _get_mode(mode)); | ||||
| 				dm_list_iterate_items(lckt, head) { | ||||
| 					if ((lckt->lockid != *lockid) && | ||||
| 					    !_dlm_table[mode][lckt->mode]) { | ||||
| 						if (!(flags & LCKF_NOQUEUE) && | ||||
| 						    /* TODO: Real dlm uses here conversion queues */ | ||||
| 						    !pthread_cond_wait(&_lock_cond, &_lock_mutex) && | ||||
| 						    _locks) /* End of the game? */ | ||||
| 							goto retry; | ||||
| 						goto bad; | ||||
| 					} | ||||
| 				} | ||||
| 				lck->mode = mode; /* Lock is now converted */ | ||||
| 				goto out; | ||||
| 			} else if (!_dlm_table[mode][lck->mode]) { | ||||
| 				DEBUGLOG("Resource %s already locked lockid=%d, mode:%s\n", | ||||
| 					 resource, lck->lockid, _get_mode(lck->mode)); | ||||
| 				if (!(flags & LCKF_NOQUEUE) && | ||||
| 				    !pthread_cond_wait(&_lock_cond, &_lock_mutex) && | ||||
| 				    _locks) { /* End of the game? */ | ||||
| 					DEBUGLOG("Resource %s retrying lock in mode:%s...\n", | ||||
| 						 resource, _get_mode(mode)); | ||||
| 					goto retry; | ||||
| 				} | ||||
| 				goto bad; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	if (!(flags & LCKF_CONVERT)) { | ||||
| 		if (!(lck = dm_malloc(sizeof(struct lock)))) | ||||
| 			goto_bad; | ||||
|  | ||||
| 		*lockid = lck->lockid = ++_lockid; | ||||
| 		lck->mode = mode; | ||||
| 		dm_list_add(head, &lck->list); | ||||
| 	} | ||||
| out: | ||||
| 	pthread_mutex_unlock(&_lock_mutex); | ||||
| 	DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n", | ||||
| 		 resource, lck->lockid, _get_mode(lck->mode)); | ||||
|  | ||||
| 	return 0; | ||||
| bad: | ||||
| 	pthread_mutex_unlock(&_lock_mutex); | ||||
| 	DEBUGLOG("Failed to lock resource %s\n", resource); | ||||
|  | ||||
| 	return 1; /* fail */ | ||||
| } | ||||
|  | ||||
| static int _unlock_resource(const char *resource, int lockid) | ||||
| { | ||||
| 	struct lock *lck; | ||||
| 	struct dm_list *head; | ||||
| 	int r = 1; | ||||
|  | ||||
| 	if (lockid < 0) { | ||||
| 		DEBUGLOG("Not tracking unlock of lockid -1: %s, lockid=%d\n", | ||||
| 			 resource, lockid); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("Unlocking resource %s, lockid=%d\n", resource, lockid); | ||||
| 	pthread_mutex_lock(&_lock_mutex); | ||||
| 	pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */ | ||||
|  | ||||
| 	if (!(head = dm_hash_lookup(_locks, resource))) { | ||||
| 		pthread_mutex_unlock(&_lock_mutex); | ||||
| 		DEBUGLOG("Resource %s is not locked.\n", resource); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	dm_list_iterate_items(lck, head) | ||||
| 		if (lck->lockid == lockid) { | ||||
| 			dm_list_del(&lck->list); | ||||
| 			dm_free(lck); | ||||
| 			r = 0; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 	DEBUGLOG("Resource %s has wrong lockid %d.\n", resource, lockid); | ||||
| out: | ||||
| 	if (dm_list_empty(head)) { | ||||
| 		//DEBUGLOG("Resource %s is no longer hashed (lockid=%d).\n", resource, lockid); | ||||
| 		dm_hash_remove(_locks, resource); | ||||
| 		dm_free(head); | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_unlock(&_lock_mutex); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _is_quorate(void) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _get_main_cluster_fd(void) | ||||
| { | ||||
| 	return listen_fd; | ||||
| } | ||||
|  | ||||
| static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, | ||||
| 				const char *csid, | ||||
| 				struct local_client **new_client) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _cluster_send_message(const void *buf, int msglen, | ||||
| 				 const char *csid, | ||||
| 				 const char *errtext) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _get_cluster_name(char *buf, int buflen) | ||||
| { | ||||
| 	return dm_strncpy(buf, "localcluster", buflen) ? 0 : 1; | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_singlenode_ops = { | ||||
| 	.name                     = "singlenode", | ||||
| 	.cluster_init_completed   = NULL, | ||||
| 	.cluster_send_message     = _cluster_send_message, | ||||
| 	.name_from_csid           = _name_from_csid, | ||||
| 	.csid_from_name           = _csid_from_name, | ||||
| 	.get_num_nodes            = _get_num_nodes, | ||||
| 	.cluster_fd_callback      = _cluster_fd_callback, | ||||
| 	.get_main_cluster_fd      = _get_main_cluster_fd, | ||||
| 	.cluster_do_node_callback = _cluster_do_node_callback, | ||||
| 	.is_quorate               = _is_quorate, | ||||
| 	.get_our_csid             = _get_our_csid, | ||||
| 	.add_up_node              = _add_up_node, | ||||
| 	.reread_config            = NULL, | ||||
| 	.cluster_closedown        = _cluster_closedown, | ||||
| 	.get_cluster_name         = _get_cluster_name, | ||||
| 	.sync_lock                = _lock_resource, | ||||
| 	.sync_unlock              = _unlock_resource, | ||||
| }; | ||||
|  | ||||
| struct cluster_ops *init_singlenode_cluster(void) | ||||
| { | ||||
| 	if (!_init_cluster()) | ||||
| 		return &_cluster_singlenode_ops; | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,126 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _CLVMD_H | ||||
| #define _CLVMD_H | ||||
|  | ||||
| #define CLVMD_MAJOR_VERSION 0 | ||||
| #define CLVMD_MINOR_VERSION 2 | ||||
| #define CLVMD_PATCH_VERSION 1 | ||||
|  | ||||
| /* Default time (in seconds) we will wait for all remote commands to execute | ||||
|    before declaring them dead */ | ||||
| #define DEFAULT_CMD_TIMEOUT 60 | ||||
|  | ||||
| /* One of these for each reply we get from command execution on a node */ | ||||
| struct node_reply { | ||||
| 	char node[MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
| 	char *replymsg; | ||||
| 	int status; | ||||
| 	struct node_reply *next; | ||||
| }; | ||||
|  | ||||
| typedef enum {DEBUG_OFF, DEBUG_STDERR, DEBUG_SYSLOG} debug_t; | ||||
|  | ||||
| /* | ||||
|  * These exist for the use of local sockets only when we are | ||||
|  * collecting responses from all cluster nodes | ||||
|  */ | ||||
| struct localsock_bits { | ||||
| 	struct node_reply *replies; | ||||
| 	int num_replies; | ||||
| 	int expected_replies; | ||||
| 	time_t sent_time;	/* So we can check for timeouts */ | ||||
| 	int in_progress;	/* Only execute one cmd at a time per client */ | ||||
| 	int sent_out;		/* Flag to indicate that a command was sent | ||||
| 				   to remote nodes */ | ||||
| 	void *private;		/* Private area for command processor use */ | ||||
| 	void *cmd;		/* Whole command as passed down local socket */ | ||||
| 	int cmd_len;		/* Length of above */ | ||||
| 	int pipe;		/* Pipe to send PRE completion status down */ | ||||
| 	int finished;		/* Flag to tell subthread to exit */ | ||||
| 	int all_success;	/* Set to 0 if any node (or the pre_command) | ||||
| 				   failed */ | ||||
| 	int cleanup_needed;     /* helper for cleanup_zombie */ | ||||
| 	struct local_client *pipe_client; | ||||
| 	pthread_t threadid; | ||||
| 	enum { PRE_COMMAND, POST_COMMAND } state; | ||||
| 	pthread_mutex_t mutex;	/* Main thread and worker synchronisation */ | ||||
| 	pthread_cond_t cond; | ||||
| }; | ||||
|  | ||||
| /* Entries for PIPE clients */ | ||||
| struct pipe_bits { | ||||
| 	struct local_client *client;	/* Actual (localsock) client */ | ||||
| 	pthread_t threadid;		/* Our own copy of the thread id */ | ||||
| }; | ||||
|  | ||||
| /* Entries for Network socket clients */ | ||||
| struct netsock_bits { | ||||
| 	void *private; | ||||
| 	int flags; | ||||
| }; | ||||
|  | ||||
| typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len, | ||||
| 			      const char *csid, | ||||
| 			      struct local_client ** new_client); | ||||
|  | ||||
| /* One of these for each fd we are listening on */ | ||||
| struct local_client { | ||||
| 	int fd; | ||||
| 	enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS, | ||||
| 		    LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type; | ||||
| 	struct local_client *next; | ||||
| 	unsigned short xid; | ||||
| 	fd_callback_t callback; | ||||
| 	uint8_t removeme; | ||||
|  | ||||
| 	union { | ||||
| 		struct localsock_bits localsock; | ||||
| 		struct pipe_bits pipe; | ||||
| 		struct netsock_bits net; | ||||
| 	} bits; | ||||
| }; | ||||
|  | ||||
| #define DEBUGLOG(fmt, args...) debuglog(fmt, ## args) | ||||
|  | ||||
| #ifndef max | ||||
| #define max(a,b) ((a)>(b)?(a):(b)) | ||||
| #endif | ||||
|  | ||||
| /* The real command processor is in clvmd-command.c */ | ||||
| extern int do_command(struct local_client *client, struct clvm_header *msg, | ||||
| 		      int msglen, char **buf, int buflen, int *retlen); | ||||
|  | ||||
| /* Pre and post command routines are called only on the local node */ | ||||
| extern int do_pre_command(struct local_client *client); | ||||
| extern int do_post_command(struct local_client *client); | ||||
| extern void cmd_client_cleanup(struct local_client *client); | ||||
| extern int add_client(struct local_client *new_client); | ||||
|  | ||||
| extern void clvmd_cluster_init_completed(void); | ||||
| extern void process_message(struct local_client *client, char *buf, | ||||
| 			    int len, const char *csid); | ||||
| extern void debuglog(const char *fmt, ... ) | ||||
|   __attribute__ ((format(printf, 1, 2))); | ||||
|  | ||||
| void clvmd_set_debug(debug_t new_de); | ||||
| debug_t clvmd_get_debug(void); | ||||
| int clvmd_get_foreground(void); | ||||
|  | ||||
| int sync_lock(const char *resource, int mode, int flags, int *lockid); | ||||
| int sync_unlock(const char *resource, int lockid); | ||||
|  | ||||
| #endif | ||||
| @@ -1,932 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| /* LVM2 headers */ | ||||
| #include "toolcontext.h" | ||||
| #include "lvmcache.h" | ||||
| #include "lvm-globals.h" | ||||
| #include "activate.h" | ||||
| #include "archiver.h" | ||||
| #include "memlock.h" | ||||
|  | ||||
| #include <syslog.h> | ||||
|  | ||||
| static struct cmd_context *cmd = NULL; | ||||
| static struct dm_hash_table *lv_hash = NULL; | ||||
| static pthread_mutex_t lv_hash_lock; | ||||
| static pthread_mutex_t lvm_lock; | ||||
| static char last_error[1024]; | ||||
|  | ||||
| struct lv_info { | ||||
| 	int lock_id; | ||||
| 	int lock_mode; | ||||
| }; | ||||
|  | ||||
| static const char *decode_full_locking_cmd(uint32_t cmdl) | ||||
| { | ||||
| 	static char buf[128]; | ||||
| 	const char *type; | ||||
| 	const char *scope; | ||||
| 	const char *command; | ||||
|  | ||||
| 	switch (cmdl & LCK_TYPE_MASK) { | ||||
| 	case LCK_NULL: | ||||
| 		type = "NULL"; | ||||
| 		break; | ||||
| 	case LCK_READ: | ||||
| 		type = "READ"; | ||||
| 		break; | ||||
| 	case LCK_PREAD: | ||||
| 		type = "PREAD"; | ||||
| 		break; | ||||
| 	case LCK_WRITE: | ||||
| 		type = "WRITE"; | ||||
| 		break; | ||||
| 	case LCK_EXCL: | ||||
| 		type = "EXCL"; | ||||
| 		break; | ||||
| 	case LCK_UNLOCK: | ||||
| 		type = "UNLOCK"; | ||||
| 		break; | ||||
| 	default: | ||||
| 		type = "unknown"; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	switch (cmdl & LCK_SCOPE_MASK) { | ||||
| 	case LCK_VG: | ||||
| 		scope = "VG"; | ||||
| 		command = "LCK_VG"; | ||||
| 		break; | ||||
| 	case LCK_LV: | ||||
| 		scope = "LV"; | ||||
| 		switch (cmdl & LCK_MASK) { | ||||
| 		case LCK_LV_EXCLUSIVE & LCK_MASK: | ||||
| 			command = "LCK_LV_EXCLUSIVE"; | ||||
| 			break; | ||||
| 		case LCK_LV_SUSPEND & LCK_MASK: | ||||
| 			command = "LCK_LV_SUSPEND"; | ||||
| 			break; | ||||
| 		case LCK_LV_RESUME & LCK_MASK: | ||||
| 			command = "LCK_LV_RESUME"; | ||||
| 			break; | ||||
| 		case LCK_LV_ACTIVATE & LCK_MASK: | ||||
| 			command = "LCK_LV_ACTIVATE"; | ||||
| 			break; | ||||
| 		case LCK_LV_DEACTIVATE & LCK_MASK: | ||||
| 			command = "LCK_LV_DEACTIVATE"; | ||||
| 			break; | ||||
| 		default: | ||||
| 			command = "unknown"; | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	default: | ||||
| 		scope = "unknown"; | ||||
| 		command = "unknown"; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	sprintf(buf, "0x%x %s (%s|%s%s%s%s%s)", cmdl, command, type, scope, | ||||
| 		cmdl & LCK_NONBLOCK   ? "|NONBLOCK" : "", | ||||
| 		cmdl & LCK_HOLD       ? "|HOLD" : "", | ||||
| 		cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "", | ||||
| 		cmdl & LCK_CACHE      ? "|CACHE" : ""); | ||||
|  | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Only processes 8 bits: excludes LCK_CACHE. | ||||
|  */ | ||||
| static const char *decode_locking_cmd(unsigned char cmdl) | ||||
| { | ||||
| 	return decode_full_locking_cmd((uint32_t) cmdl); | ||||
| } | ||||
|  | ||||
| static const char *decode_flags(unsigned char flags) | ||||
| { | ||||
| 	static char buf[128]; | ||||
| 	int len; | ||||
|  | ||||
| 	len = sprintf(buf, "0x%x ( %s%s%s%s%s%s%s%s)", flags, | ||||
| 		flags & LCK_PARTIAL_MODE	  ? "PARTIAL_MODE|" : "", | ||||
| 		flags & LCK_MIRROR_NOSYNC_MODE	  ? "MIRROR_NOSYNC|" : "", | ||||
| 		flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "", | ||||
| 		flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "", | ||||
| 		flags & LCK_TEST_MODE ? "TEST|" : "", | ||||
| 		flags & LCK_CONVERT ? "CONVERT|" : "", | ||||
| 		flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "", | ||||
| 		flags & LCK_REVERT_MODE ? "REVERT|" : ""); | ||||
|  | ||||
| 	if (len > 1) | ||||
| 		buf[len - 2] = ' '; | ||||
| 	else | ||||
| 		buf[0] = '\0'; | ||||
|  | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| char *get_last_lvm_error(void) | ||||
| { | ||||
| 	return last_error; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Hash lock info helpers | ||||
|  */ | ||||
| static struct lv_info *lookup_info(const char *resource) | ||||
| { | ||||
| 	struct lv_info *lvi; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	lvi = dm_hash_lookup(lv_hash, resource); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
|  | ||||
| 	return lvi; | ||||
| } | ||||
|  | ||||
| static int insert_info(const char *resource, struct lv_info *lvi) | ||||
| { | ||||
| 	int ret; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	ret = dm_hash_insert(lv_hash, resource, lvi); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static void remove_info(const char *resource) | ||||
| { | ||||
| 	int num_open; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	dm_hash_remove(lv_hash, resource); | ||||
|  | ||||
| 	/* When last lock is remove, validate there are not left opened devices */ | ||||
| 	if (!dm_hash_get_first(lv_hash)) { | ||||
| 		if (critical_section()) | ||||
| 			log_error(INTERNAL_ERROR "No volumes are locked however clvmd is in activation mode critical section."); | ||||
| 		if ((num_open = dev_cache_check_for_open_devices())) | ||||
| 			log_error(INTERNAL_ERROR "No volumes are locked however %d devices are still open.", num_open); | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return the mode a lock is currently held at (or -1 if not held) | ||||
|  */ | ||||
| static int get_current_lock(char *resource) | ||||
| { | ||||
| 	struct lv_info *lvi; | ||||
|  | ||||
| 	if ((lvi = lookup_info(resource))) | ||||
| 		return lvi->lock_mode; | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
|  | ||||
| void init_lvhash(void) | ||||
| { | ||||
| 	/* Create hash table for keeping LV locks & status */ | ||||
| 	lv_hash = dm_hash_create(1024); | ||||
| 	pthread_mutex_init(&lv_hash_lock, NULL); | ||||
| 	pthread_mutex_init(&lvm_lock, NULL); | ||||
| } | ||||
|  | ||||
| /* Called at shutdown to tidy the lockspace */ | ||||
| void destroy_lvhash(void) | ||||
| { | ||||
| 	struct dm_hash_node *v; | ||||
| 	struct lv_info *lvi; | ||||
| 	char *resource; | ||||
| 	int status; | ||||
|  | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
|  | ||||
| 	dm_hash_iterate(v, lv_hash) { | ||||
| 		lvi = dm_hash_get_data(lv_hash, v); | ||||
| 		resource = dm_hash_get_key(lv_hash, v); | ||||
|  | ||||
| 		if ((status = sync_unlock(resource, lvi->lock_id))) | ||||
| 			DEBUGLOG("unlock_all. unlock failed(%d): %s\n", | ||||
| 				 status,  strerror(errno)); | ||||
| 		dm_free(lvi); | ||||
| 	} | ||||
|  | ||||
| 	dm_hash_destroy(lv_hash); | ||||
| 	lv_hash = NULL; | ||||
|  | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| } | ||||
|  | ||||
| /* Gets a real lock and keeps the info in the hash table */ | ||||
| static int hold_lock(char *resource, int mode, int flags) | ||||
| { | ||||
| 	int status; | ||||
| 	int saved_errno; | ||||
| 	struct lv_info *lvi; | ||||
|  | ||||
| 	/* Mask off invalid options */ | ||||
| 	flags &= LCKF_NOQUEUE | LCKF_CONVERT; | ||||
|  | ||||
| 	lvi = lookup_info(resource); | ||||
|  | ||||
| 	if (lvi) { | ||||
| 		if (lvi->lock_mode == mode) { | ||||
| 			DEBUGLOG("hold_lock, lock mode %d already held\n", | ||||
| 				 mode); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) { | ||||
| 			DEBUGLOG("hold_lock, lock already held LCK_EXCL, " | ||||
| 				 "ignoring LCK_WRITE request\n"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Only allow explicit conversions */ | ||||
| 	if (lvi && !(flags & LCKF_CONVERT)) { | ||||
| 		errno = EBUSY; | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (lvi) { | ||||
| 		/* Already exists - convert it */ | ||||
| 		status = sync_lock(resource, mode, flags, &lvi->lock_id); | ||||
| 		saved_errno = errno; | ||||
| 		if (!status) | ||||
| 			lvi->lock_mode = mode; | ||||
| 		else | ||||
| 			DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode, | ||||
| 				 strerror(errno)); | ||||
| 		errno = saved_errno; | ||||
| 	} else { | ||||
| 		if (!(lvi = dm_malloc(sizeof(struct lv_info)))) { | ||||
| 			errno = ENOMEM; | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		lvi->lock_mode = mode; | ||||
| 		status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id); | ||||
| 		saved_errno = errno; | ||||
| 		if (status) { | ||||
| 			dm_free(lvi); | ||||
| 			DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode, | ||||
| 				 strerror(errno)); | ||||
| 		} else | ||||
| 			if (!insert_info(resource, lvi)) { | ||||
| 				errno = ENOMEM; | ||||
| 				return -1; | ||||
| 			} | ||||
|  | ||||
| 		errno = saved_errno; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Unlock and remove it from the hash table */ | ||||
| static int hold_unlock(char *resource) | ||||
| { | ||||
| 	struct lv_info *lvi; | ||||
| 	int status; | ||||
| 	int saved_errno; | ||||
|  | ||||
| 	if (!(lvi = lookup_info(resource))) { | ||||
| 		DEBUGLOG("hold_unlock, lock not already held\n"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	status = sync_unlock(resource, lvi->lock_id); | ||||
| 	saved_errno = errno; | ||||
| 	if (!status) { | ||||
| 		remove_info(resource); | ||||
| 		dm_free(lvi); | ||||
| 	} else { | ||||
| 		DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status, | ||||
| 			 strerror(errno)); | ||||
| 	} | ||||
|  | ||||
| 	errno = saved_errno; | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Watch the return codes here. | ||||
|    liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno. | ||||
|    libdlm API functions return 0 for success, -1 for failure and do set errno. | ||||
|    These functions here return 0 for success or >0 for failure (where the retcode is errno) | ||||
| */ | ||||
|  | ||||
| /* Activate LV exclusive or non-exclusive */ | ||||
| static int do_activate_lv(char *resource, unsigned char command, unsigned char lock_flags, int mode) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
| 	int activate_lv; | ||||
| 	int exclusive = 0; | ||||
| 	struct lvinfo lvi; | ||||
|  | ||||
| 	/* Is it already open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == mode && (command & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("do_activate_lv, lock already held at %d\n", oldmode); | ||||
| 		return 0;	/* Nothing to do */ | ||||
| 	} | ||||
|  | ||||
| 	/* Does the config file want us to activate this LV ? */ | ||||
| 	if (!lv_activation_filter(cmd, resource, &activate_lv, NULL)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (!activate_lv) | ||||
| 		return 0;	/* Success, we did nothing! */ | ||||
|  | ||||
| 	/* Do we need to activate exclusively? */ | ||||
| 	if ((activate_lv == 2) || (mode == LCK_EXCL)) { | ||||
| 		exclusive = 1; | ||||
| 		mode = LCK_EXCL; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Try to get the lock if it's a clustered volume group. | ||||
| 	 * Use lock conversion only if requested, to prevent implicit conversion | ||||
| 	 * of exclusive lock to shared one during activation. | ||||
| 	 */ | ||||
| 	if (!test_mode() && command & LCK_CLUSTER_VG) { | ||||
| 		status = hold_lock(resource, mode, LCKF_NOQUEUE | (lock_flags & LCK_CONVERT ? LCKF_CONVERT:0)); | ||||
| 		if (status) { | ||||
| 			/* Return an LVM-sensible error for this. | ||||
| 			 * Forcing EIO makes the upper level return this text | ||||
| 			 * rather than the strerror text for EAGAIN. | ||||
| 			 */ | ||||
| 			if (errno == EAGAIN) { | ||||
| 				sprintf(last_error, "Volume is busy on another node"); | ||||
| 				errno = EIO; | ||||
| 			} | ||||
| 			return errno; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* If it's suspended then resume it */ | ||||
| 	if (!lv_info_by_lvid(cmd, resource, 0, &lvi, 0, 0)) | ||||
| 		goto error; | ||||
|  | ||||
| 	if (lvi.suspended) { | ||||
| 		critical_section_inc(cmd, "resuming"); | ||||
| 		if (!lv_resume(cmd, resource, 0, NULL)) { | ||||
| 			critical_section_dec(cmd, "resumed"); | ||||
| 			goto error; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Now activate it */ | ||||
| 	if (!lv_activate(cmd, resource, exclusive, 0, 0, NULL)) | ||||
| 		goto error; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| error: | ||||
| 	if (!test_mode() && (oldmode == -1 || oldmode != mode)) | ||||
| 		(void)hold_unlock(resource); | ||||
| 	return EIO; | ||||
| } | ||||
|  | ||||
| /* Resume the LV if it was active */ | ||||
| static int do_resume_lv(char *resource, unsigned char command, unsigned char lock_flags) | ||||
| { | ||||
| 	int oldmode, origin_only, exclusive, revert; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("do_resume_lv, lock not already held\n"); | ||||
| 		return 0;	/* We don't need to do anything */ | ||||
| 	} | ||||
| 	origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0; | ||||
| 	exclusive = (oldmode == LCK_EXCL) ? 1 : 0; | ||||
| 	revert = (lock_flags & LCK_REVERT_MODE) ? 1 : 0; | ||||
|  | ||||
| 	if (!lv_resume_if_active(cmd, resource, origin_only, exclusive, revert, NULL)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Suspend the device if active */ | ||||
| static int do_suspend_lv(char *resource, unsigned char command, unsigned char lock_flags) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0; | ||||
| 	unsigned exclusive; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("do_suspend_lv, lock not already held\n"); | ||||
| 		return 0; /* Not active, so it's OK */ | ||||
| 	} | ||||
|  | ||||
| 	exclusive = (oldmode == LCK_EXCL) ? 1 : 0; | ||||
|  | ||||
| 	/* Always call lv_suspend to read commited and precommited data */ | ||||
| 	if (!lv_suspend_if_active(cmd, resource, origin_only, exclusive, NULL, NULL)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int do_deactivate_lv(char *resource, unsigned char command, unsigned char lock_flags) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("do_deactivate_lock, lock not already held\n"); | ||||
| 		return 0;	/* We don't need to do anything */ | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_deactivate(cmd, resource, NULL)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (!test_mode() && command & LCK_CLUSTER_VG) { | ||||
| 		status = hold_unlock(resource); | ||||
| 		if (status) | ||||
| 			return errno; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| const char *do_lock_query(char *resource) | ||||
| { | ||||
| 	int mode; | ||||
| 	const char *type; | ||||
|  | ||||
| 	mode = get_current_lock(resource); | ||||
| 	switch (mode) { | ||||
| 	case LCK_NULL: type = "NL"; break; | ||||
| 	case LCK_READ: type = "CR"; break; | ||||
| 	case LCK_PREAD:type = "PR"; break; | ||||
| 	case LCK_WRITE:type = "PW"; break; | ||||
| 	case LCK_EXCL: type = "EX"; break; | ||||
| 	default: type = NULL; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGLOG("do_lock_query: resource '%s', mode %i (%s)\n", resource, mode, type ?: "--"); | ||||
|  | ||||
| 	return type; | ||||
| } | ||||
|  | ||||
| /* This is the LOCK_LV part that happens on all nodes in the cluster - | ||||
|    it is responsible for the interaction with device-mapper and LVM */ | ||||
| int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource) | ||||
| { | ||||
| 	int status = 0; | ||||
|  | ||||
| 	DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n", | ||||
| 		 resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section()); | ||||
|  | ||||
| 	if (!cmd->config_initialized || config_files_changed(cmd)) { | ||||
| 		/* Reinitialise various settings inc. logging, filters */ | ||||
| 		if (do_refresh_cache()) { | ||||
| 			log_error("Updated config file invalid. Aborting."); | ||||
| 			return EINVAL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_lock(&lvm_lock); | ||||
| 	init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0); | ||||
|  | ||||
| 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE) | ||||
| 		init_mirror_in_sync(1); | ||||
|  | ||||
| 	if (lock_flags & LCK_DMEVENTD_MONITOR_IGNORE) | ||||
| 		init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE); | ||||
| 	else { | ||||
| 		if (lock_flags & LCK_DMEVENTD_MONITOR_MODE) | ||||
| 			init_dmeventd_monitor(1); | ||||
| 		else | ||||
| 			init_dmeventd_monitor(0); | ||||
| 	} | ||||
|  | ||||
| 	cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0; | ||||
|  | ||||
| 	/* clvmd should never try to read suspended device */ | ||||
| 	init_ignore_suspended_devices(1); | ||||
|  | ||||
| 	switch (command & LCK_MASK) { | ||||
| 	case LCK_LV_EXCLUSIVE: | ||||
| 		status = do_activate_lv(resource, command, lock_flags, LCK_EXCL); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_SUSPEND: | ||||
| 		status = do_suspend_lv(resource, command, lock_flags); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_UNLOCK: | ||||
| 	case LCK_LV_RESUME:	/* if active */ | ||||
| 		status = do_resume_lv(resource, command, lock_flags); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_ACTIVATE: | ||||
| 		status = do_activate_lv(resource, command, lock_flags, LCK_READ); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_DEACTIVATE: | ||||
| 		status = do_deactivate_lv(resource, command, lock_flags); | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		DEBUGLOG("Invalid LV command 0x%x\n", command); | ||||
| 		status = EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE) | ||||
| 		init_mirror_in_sync(0); | ||||
|  | ||||
| 	cmd->partial_activation = 0; | ||||
|  | ||||
| 	/* clean the pool for another command */ | ||||
| 	dm_pool_empty(cmd->mem); | ||||
| 	init_test(0); | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
|  | ||||
| 	DEBUGLOG("Command return is %d, critical_section is %d\n", status, critical_section()); | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */ | ||||
| int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource) | ||||
| { | ||||
| 	/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the | ||||
| 	   lock out on this node (because we are the node modifying the metadata) | ||||
| 	   before suspending cluster-wide. | ||||
| 	   LCKF_CONVERT is used always, local node is going to modify metadata | ||||
| 	 */ | ||||
| 	if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND && | ||||
| 	    (command & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n", | ||||
| 			 resource, decode_locking_cmd(command), decode_flags(lock_flags)); | ||||
|  | ||||
| 		if (!(lock_flags & LCK_TEST_MODE) && | ||||
| 		    hold_lock(resource, LCK_WRITE, LCKF_NOQUEUE | LCKF_CONVERT)) | ||||
| 			return errno; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Functions to do on the local node only AFTER the cluster-wide stuff above happens */ | ||||
| int post_lock_lv(unsigned char command, unsigned char lock_flags, | ||||
| 		 char *resource) | ||||
| { | ||||
| 	int status; | ||||
| 	unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0; | ||||
|  | ||||
| 	/* Opposite of above, done on resume after a metadata update */ | ||||
| 	if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME && | ||||
| 	    (command & LCK_CLUSTER_VG)) { | ||||
| 		int oldmode; | ||||
|  | ||||
| 		DEBUGLOG("post_lock_lv: resource '%s', cmd = %s, flags = %s\n", | ||||
| 			 resource, decode_locking_cmd(command), decode_flags(lock_flags)); | ||||
|  | ||||
| 		/* If the lock state is PW then restore it to what it was */ | ||||
| 		oldmode = get_current_lock(resource); | ||||
| 		if (oldmode == LCK_WRITE) { | ||||
| 			struct lvinfo lvi; | ||||
|  | ||||
| 			pthread_mutex_lock(&lvm_lock); | ||||
| 			status = lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0); | ||||
| 			pthread_mutex_unlock(&lvm_lock); | ||||
| 			if (!status) | ||||
| 				return EIO; | ||||
|  | ||||
| 			if (!(lock_flags & LCK_TEST_MODE)) { | ||||
| 				if (lvi.exists) { | ||||
| 					if (hold_lock(resource, LCK_READ, LCKF_CONVERT)) | ||||
| 						return errno; | ||||
| 				} else if (hold_unlock(resource)) | ||||
| 					return errno; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Check if a VG is in use by LVM1 so we don't stomp on it */ | ||||
| int do_check_lvm1(const char *vgname) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	status = check_lvm1_vg_inactive(cmd, vgname); | ||||
|  | ||||
| 	return status == 1 ? 0 : EBUSY; | ||||
| } | ||||
|  | ||||
| int do_refresh_cache(void) | ||||
| { | ||||
| 	DEBUGLOG("Refreshing context\n"); | ||||
| 	log_notice("Refreshing context"); | ||||
|  | ||||
| 	pthread_mutex_lock(&lvm_lock); | ||||
|  | ||||
| 	if (!refresh_toolcontext(cmd)) { | ||||
| 		pthread_mutex_unlock(&lvm_lock); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	init_full_scan_done(0); | ||||
| 	init_ignore_suspended_devices(1); | ||||
| 	lvmcache_label_scan(cmd, 2); | ||||
| 	dm_pool_empty(cmd->mem); | ||||
|  | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Handle VG lock - drop metadata or update lvmcache state | ||||
|  */ | ||||
| void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource) | ||||
| { | ||||
| 	uint32_t lock_cmd = command; | ||||
| 	char *vgname = resource + 2; | ||||
|  | ||||
| 	lock_cmd &= (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_HOLD); | ||||
|  | ||||
| 	/* | ||||
| 	 * Check if LCK_CACHE should be set. All P_ locks except # are cache related. | ||||
| 	 */ | ||||
| 	if (strncmp(resource, "P_#", 3) && !strncmp(resource, "P_", 2)) | ||||
| 		lock_cmd |= LCK_CACHE; | ||||
|  | ||||
| 	DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, critical_section = %d\n", | ||||
| 		 resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), critical_section()); | ||||
|  | ||||
| 	/* P_#global causes a full cache refresh */ | ||||
| 	if (!strcmp(resource, "P_" VG_GLOBAL)) { | ||||
| 		do_refresh_cache(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_lock(&lvm_lock); | ||||
| 	init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0); | ||||
|  | ||||
| 	switch (lock_cmd) { | ||||
| 		case LCK_VG_COMMIT: | ||||
| 			DEBUGLOG("vg_commit notification for VG %s\n", vgname); | ||||
| 			lvmcache_commit_metadata(vgname); | ||||
| 			break; | ||||
| 		case LCK_VG_REVERT: | ||||
| 			DEBUGLOG("vg_revert notification for VG %s\n", vgname); | ||||
| 			lvmcache_drop_metadata(vgname, 1); | ||||
| 			break; | ||||
| 		case LCK_VG_DROP_CACHE: | ||||
| 		default: | ||||
| 			DEBUGLOG("Invalidating cached metadata for VG %s\n", vgname); | ||||
| 			lvmcache_drop_metadata(vgname, 0); | ||||
| 	} | ||||
|  | ||||
| 	init_test(0); | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Ideally, clvmd should be started before any LVs are active | ||||
|  * but this may not be the case... | ||||
|  * I suppose this also comes in handy if clvmd crashes, not that it would! | ||||
|  */ | ||||
| static int get_initial_state(struct dm_hash_table *excl_uuid) | ||||
| { | ||||
| 	int lock_mode; | ||||
| 	char lv[65], vg[65], flags[26], vg_flags[26]; /* with space for '\0' */ | ||||
| 	char uuid[65]; | ||||
| 	char line[255]; | ||||
| 	char *lvs_cmd; | ||||
| 	const char *lvm_binary = getenv("LVM_BINARY") ? : LVM_PATH; | ||||
| 	FILE *lvs; | ||||
|  | ||||
| 	if (dm_asprintf(&lvs_cmd, "%s lvs  --config 'log{command_names=0 prefix=\"\"}' " | ||||
| 			"--nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr", | ||||
| 			lvm_binary) < 0) | ||||
| 		return_0; | ||||
|  | ||||
| 	/* FIXME: Maybe link and use liblvm2cmd directly instead of fork */ | ||||
| 	if (!(lvs = popen(lvs_cmd, "r"))) { | ||||
| 		dm_free(lvs_cmd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), lvs)) { | ||||
| 	        if (sscanf(line, "%64s %64s %25s %25s\n", vg, lv, flags, vg_flags) == 4) { | ||||
|  | ||||
| 			/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */ | ||||
| 		        if (strlen(vg) == 38 &&                         /* is is a valid UUID ? */ | ||||
| 			    (flags[4] == 'a' || flags[4] == 's') &&	/* is it active or suspended? */ | ||||
| 			    vg_flags[5] == 'c') {			/* is it clustered ? */ | ||||
| 				/* Convert hyphen-separated UUIDs into one */ | ||||
| 				memcpy(&uuid[0], &vg[0], 6); | ||||
| 				memcpy(&uuid[6], &vg[7], 4); | ||||
| 				memcpy(&uuid[10], &vg[12], 4); | ||||
| 				memcpy(&uuid[14], &vg[17], 4); | ||||
| 				memcpy(&uuid[18], &vg[22], 4); | ||||
| 				memcpy(&uuid[22], &vg[27], 4); | ||||
| 				memcpy(&uuid[26], &vg[32], 6); | ||||
| 				memcpy(&uuid[32], &lv[0], 6); | ||||
| 				memcpy(&uuid[38], &lv[7], 4); | ||||
| 				memcpy(&uuid[42], &lv[12], 4); | ||||
| 				memcpy(&uuid[46], &lv[17], 4); | ||||
| 				memcpy(&uuid[50], &lv[22], 4); | ||||
| 				memcpy(&uuid[54], &lv[27], 4); | ||||
| 				memcpy(&uuid[58], &lv[32], 6); | ||||
| 				uuid[64] = '\0'; | ||||
|  | ||||
| 				/* Look for this lock in the list of EX locks | ||||
| 				   we were passed on the command-line */ | ||||
| 				lock_mode = (dm_hash_lookup(excl_uuid, uuid)) ? | ||||
| 					LCK_EXCL : LCK_READ; | ||||
|  | ||||
| 				DEBUGLOG("getting initial lock for %s\n", uuid); | ||||
| 				if (hold_lock(uuid, lock_mode, LCKF_NOQUEUE)) | ||||
| 					DEBUGLOG("Failed to hold lock %s\n", uuid); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if (pclose(lvs)) | ||||
| 		DEBUGLOG("lvs pclose failed: %s\n", strerror(errno)); | ||||
|  | ||||
| 	dm_free(lvs_cmd); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void lvm2_log_fn(int level, const char *file, int line, int dm_errno, | ||||
| 			const char *message) | ||||
| { | ||||
|  | ||||
| 	/* Send messages to the normal LVM2 logging system too, | ||||
| 	   so we get debug output when it's asked for. | ||||
|  	   We need to NULL the function ptr otherwise it will just call | ||||
| 	   back into here! */ | ||||
| 	init_log_fn(NULL); | ||||
| 	print_log(level, file, line, dm_errno, "%s", message); | ||||
| 	init_log_fn(lvm2_log_fn); | ||||
|  | ||||
| 	/* | ||||
| 	 * Ignore non-error messages, but store the latest one for returning | ||||
| 	 * to the user. | ||||
| 	 */ | ||||
| 	if (level != _LOG_ERR && level != _LOG_FATAL) | ||||
| 		return; | ||||
|  | ||||
| 	strncpy(last_error, message, sizeof(last_error)); | ||||
| 	last_error[sizeof(last_error)-1] = '\0'; | ||||
| } | ||||
|  | ||||
| /* This checks some basic cluster-LVM configuration stuff */ | ||||
| static void check_config(void) | ||||
| { | ||||
| 	int locking_type; | ||||
|  | ||||
| 	locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL); | ||||
|  | ||||
| 	if (locking_type == 3) /* compiled-in cluster support */ | ||||
| 		return; | ||||
|  | ||||
| 	if (locking_type == 2) { /* External library, check name */ | ||||
| 		const char *libname; | ||||
|  | ||||
| 		libname = find_config_tree_str(cmd, global_locking_library_CFG, NULL); | ||||
| 		if (libname && strstr(libname, "liblvm2clusterlock.so")) | ||||
| 			return; | ||||
|  | ||||
| 		log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work."); | ||||
| 		return; | ||||
| 	} | ||||
| 	log_error("locking_type not set correctly in lvm.conf, cluster operations will not work."); | ||||
| } | ||||
|  | ||||
| /* Backups up the LVM metadata if it's changed */ | ||||
| void lvm_do_backup(const char *vgname) | ||||
| { | ||||
| 	struct volume_group * vg; | ||||
| 	int consistent = 0; | ||||
|  | ||||
| 	DEBUGLOG("Triggering backup of VG metadata for %s.\n", vgname); | ||||
|  | ||||
| 	pthread_mutex_lock(&lvm_lock); | ||||
|  | ||||
| 	vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 1, &consistent); | ||||
|  | ||||
| 	if (vg && consistent) | ||||
| 		check_current_backup(vg); | ||||
| 	else | ||||
| 		log_error("Error backing up metadata, can't find VG for group %s", vgname); | ||||
|  | ||||
| 	release_vg(vg); | ||||
| 	dm_pool_empty(cmd->mem); | ||||
|  | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
| } | ||||
|  | ||||
| struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name) | ||||
| { | ||||
| 	struct lv_info *lvi; | ||||
|  | ||||
| 	*name = NULL; | ||||
| 	if (!v) | ||||
| 		v = dm_hash_get_first(lv_hash); | ||||
|  | ||||
| 	do { | ||||
| 		if (v) { | ||||
| 			lvi = dm_hash_get_data(lv_hash, v); | ||||
| 			DEBUGLOG("Looking for EX locks. found %x mode %d\n", lvi->lock_id, lvi->lock_mode); | ||||
|  | ||||
| 			if (lvi->lock_mode == LCK_EXCL) { | ||||
| 				*name = dm_hash_get_key(lv_hash, v); | ||||
| 			} | ||||
| 			v = dm_hash_get_next(lv_hash, v); | ||||
| 		} | ||||
| 	} while (v && !*name); | ||||
|  | ||||
| 	if (*name) | ||||
| 		DEBUGLOG("returning EXclusive UUID %s\n", *name); | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| void lvm_do_fs_unlock(void) | ||||
| { | ||||
| 	pthread_mutex_lock(&lvm_lock); | ||||
| 	DEBUGLOG("Syncing device names\n"); | ||||
| 	fs_unlock(); | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
| } | ||||
|  | ||||
| /* Called to initialise the LVM context of the daemon */ | ||||
| int init_clvm(struct dm_hash_table *excl_uuid) | ||||
| { | ||||
| 	/* Use LOG_DAEMON for syslog messages instead of LOG_USER */ | ||||
| 	init_syslog(LOG_DAEMON); | ||||
| 	openlog("clvmd", LOG_PID, LOG_DAEMON); | ||||
|  | ||||
| 	/* Initialise already held locks */ | ||||
| 	if (!get_initial_state(excl_uuid)) | ||||
| 		log_error("Cannot load initial lock states."); | ||||
|  | ||||
| 	if (!(cmd = create_toolcontext(1, NULL, 0, 1))) { | ||||
| 		log_error("Failed to allocate command context"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (stored_errno()) { | ||||
| 		destroy_toolcontext(cmd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	cmd->cmd_line = "clvmd"; | ||||
|  | ||||
| 	/* Check lvm.conf is setup for cluster-LVM */ | ||||
| 	check_config(); | ||||
| 	init_ignore_suspended_devices(1); | ||||
|  | ||||
| 	/* Trap log messages so we can pass them back to the user */ | ||||
| 	init_log_fn(lvm2_log_fn); | ||||
| 	memlock_inc_daemon(cmd); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void destroy_lvm(void) | ||||
| { | ||||
| 	if (cmd) { | ||||
| 		memlock_dec_daemon(cmd); | ||||
| 		destroy_toolcontext(cmd); | ||||
| 		cmd = NULL; | ||||
| 	} | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* Functions in lvm-functions.c */ | ||||
|  | ||||
| #ifndef _LVM_FUNCTIONS_H | ||||
| #define _LVM_FUNCTIONS_H | ||||
|  | ||||
| extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 		       char *resource); | ||||
| extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 		      char *resource); | ||||
| extern const char *do_lock_query(char *resource); | ||||
| extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags, | ||||
| 			char *resource); | ||||
| extern int do_check_lvm1(const char *vgname); | ||||
| extern int do_refresh_cache(void); | ||||
| extern int init_clvm(struct dm_hash_table *excl_uuid); | ||||
| extern void destroy_lvm(void); | ||||
| extern void init_lvhash(void); | ||||
| extern void destroy_lvhash(void); | ||||
| extern void lvm_do_backup(const char *vgname); | ||||
| extern char *get_last_lvm_error(void); | ||||
| extern void do_lock_vg(unsigned char command, unsigned char lock_flags, | ||||
| 		      char *resource); | ||||
| extern struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name); | ||||
| void lvm_do_fs_unlock(void); | ||||
|  | ||||
| #endif | ||||
| @@ -1,382 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* FIXME Remove duplicated functions from this file. */ | ||||
|  | ||||
| /* | ||||
|  * Send a command to a running clvmd from the command-line | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include "clvm.h" | ||||
| #include "refresh_clvmd.h" | ||||
|  | ||||
| #include <stddef.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/un.h> | ||||
|  | ||||
| typedef struct lvm_response { | ||||
| 	char node[255]; | ||||
| 	char *response; | ||||
| 	int status; | ||||
| 	int len; | ||||
| } lvm_response_t; | ||||
|  | ||||
| /* | ||||
|  * This gets stuck at the start of memory we allocate so we | ||||
|  * can sanity-check it at deallocation time | ||||
|  */ | ||||
| #define LVM_SIGNATURE 0x434C564D | ||||
|  | ||||
| static int _clvmd_sock = -1; | ||||
|  | ||||
| /* Open connection to the clvm daemon */ | ||||
| static int _open_local_sock(void) | ||||
| { | ||||
| 	int local_socket; | ||||
| 	struct sockaddr_un sockaddr = { .sun_family = AF_UNIX }; | ||||
|  | ||||
| 	if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) { | ||||
| 		fprintf(stderr, "%s: clvmd socket name too long.", CLVMD_SOCKNAME); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* Open local socket */ | ||||
| 	if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { | ||||
| 		fprintf(stderr, "Local socket creation failed: %s", strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (connect(local_socket,(struct sockaddr *) &sockaddr, | ||||
| 		    sizeof(sockaddr))) { | ||||
| 		int saved_errno = errno; | ||||
|  | ||||
| 		fprintf(stderr, "connect() failed on local socket: %s\n", | ||||
| 			  strerror(errno)); | ||||
| 		if (close(local_socket)) | ||||
| 			return -1; | ||||
|  | ||||
| 		errno = saved_errno; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return local_socket; | ||||
| } | ||||
|  | ||||
| /* Send a request and return the status */ | ||||
| static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_response) | ||||
| { | ||||
| 	char outbuf[PIPE_BUF]; | ||||
| 	struct clvm_header *outheader = (struct clvm_header *) outbuf; | ||||
| 	int len; | ||||
| 	unsigned off; | ||||
| 	int buflen; | ||||
| 	int err; | ||||
|  | ||||
| 	/* Send it to CLVMD */ | ||||
|  rewrite: | ||||
| 	if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) { | ||||
| 	        if (err == -1 && errno == EINTR) | ||||
| 		        goto rewrite; | ||||
| 		fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (no_response) | ||||
| 		return 1; | ||||
|  | ||||
| 	/* Get the response */ | ||||
|  reread: | ||||
| 	if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) { | ||||
| 	        if (errno == EINTR) | ||||
| 		        goto reread; | ||||
| 		fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (len == 0) { | ||||
| 		fprintf(stderr, "EOF reading CLVMD"); | ||||
| 		errno = ENOTCONN; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Allocate buffer */ | ||||
| 	buflen = len + outheader->arglen; | ||||
| 	*retbuf = dm_malloc(buflen); | ||||
| 	if (!*retbuf) { | ||||
| 		errno = ENOMEM; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Copy the header */ | ||||
| 	memcpy(*retbuf, outbuf, len); | ||||
| 	outheader = (struct clvm_header *) *retbuf; | ||||
|  | ||||
| 	/* Read the returned values */ | ||||
| 	off = 1;		/* we've already read the first byte */ | ||||
| 	while (off <= outheader->arglen && len > 0) { | ||||
| 		len = read(_clvmd_sock, outheader->args + off, | ||||
| 			   buflen - off - offsetof(struct clvm_header, args)); | ||||
| 		if (len > 0) | ||||
| 			off += len; | ||||
| 	} | ||||
|  | ||||
| 	/* Was it an error ? */ | ||||
| 	if (outheader->status != 0) { | ||||
| 		errno = outheader->status; | ||||
|  | ||||
| 		/* Only return an error here if there are no node-specific | ||||
| 		   errors present in the message that might have more detail */ | ||||
| 		if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) { | ||||
| 			fprintf(stderr, "cluster request failed: %s\n", strerror(errno)); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Build the structure header and parse-out wildcard node names */ | ||||
| static void _build_header(struct clvm_header *head, int cmd, const char *node, | ||||
| 			  unsigned int len) | ||||
| { | ||||
| 	head->cmd = cmd; | ||||
| 	head->status = 0; | ||||
| 	head->flags = 0; | ||||
| 	head->xid = 0; | ||||
| 	head->clientid = 0; | ||||
| 	if (len) | ||||
| 		/* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */ | ||||
| 		head->arglen = len - 1; | ||||
| 	else { | ||||
| 		head->arglen = 0; | ||||
| 		*head->args = '\0'; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Translate special node names. | ||||
| 	 */ | ||||
| 	if (!node || !strcmp(node, NODE_ALL)) | ||||
| 		head->node[0] = '\0'; | ||||
| 	else if (!strcmp(node, NODE_LOCAL)) { | ||||
| 		head->node[0] = '\0'; | ||||
| 		head->flags = CLVMD_FLAG_LOCAL; | ||||
| 	} else | ||||
| 		strcpy(head->node, node); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Send a message to a(or all) node(s) in the cluster and wait for replies | ||||
|  */ | ||||
| static int _cluster_request(char cmd, const char *node, void *data, int len, | ||||
| 			    lvm_response_t ** response, int *num, int no_response) | ||||
| { | ||||
| 	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1]; | ||||
| 	char *inptr; | ||||
| 	char *retbuf = NULL; | ||||
| 	int status; | ||||
| 	int i; | ||||
| 	int num_responses = 0; | ||||
| 	struct clvm_header *head = (struct clvm_header *) outbuf; | ||||
| 	lvm_response_t *rarray; | ||||
|  | ||||
| 	*num = 0; | ||||
|  | ||||
| 	if (_clvmd_sock == -1) | ||||
| 		_clvmd_sock = _open_local_sock(); | ||||
|  | ||||
| 	if (_clvmd_sock == -1) | ||||
| 		return 0; | ||||
|  | ||||
| 	_build_header(head, cmd, node, len); | ||||
| 	if (len) | ||||
| 		memcpy(head->node + strlen(head->node) + 1, data, len); | ||||
|  | ||||
| 	status = _send_request(outbuf, sizeof(struct clvm_header) + | ||||
| 			       strlen(head->node) + len, &retbuf, no_response); | ||||
| 	if (!status || no_response) | ||||
| 		goto out; | ||||
|  | ||||
| 	/* Count the number of responses we got */ | ||||
| 	head = (struct clvm_header *) retbuf; | ||||
| 	inptr = head->args; | ||||
| 	while (inptr[0]) { | ||||
| 		num_responses++; | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 		inptr += sizeof(int); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Allocate response array. | ||||
| 	 * With an extra pair of INTs on the front to sanity | ||||
| 	 * check the pointer when we are given it back to free | ||||
| 	 */ | ||||
| 	*response = NULL; | ||||
| 	if (!(rarray = dm_malloc(sizeof(lvm_response_t) * num_responses + | ||||
| 				 sizeof(int) * 2))) { | ||||
| 		errno = ENOMEM; | ||||
| 		status = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	/* Unpack the response into an lvm_response_t array */ | ||||
| 	inptr = head->args; | ||||
| 	i = 0; | ||||
| 	while (inptr[0]) { | ||||
| 		strcpy(rarray[i].node, inptr); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
|  | ||||
| 		memcpy(&rarray[i].status, inptr, sizeof(int)); | ||||
| 		inptr += sizeof(int); | ||||
|  | ||||
| 		rarray[i].response = dm_malloc(strlen(inptr) + 1); | ||||
| 		if (rarray[i].response == NULL) { | ||||
| 			/* Free up everything else and return error */ | ||||
| 			int j; | ||||
| 			for (j = 0; j < i; j++) | ||||
| 				dm_free(rarray[i].response); | ||||
| 			dm_free(rarray); | ||||
| 			errno = ENOMEM; | ||||
| 			status = 0; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		strcpy(rarray[i].response, inptr); | ||||
| 		rarray[i].len = strlen(inptr); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 		i++; | ||||
| 	} | ||||
| 	*num = num_responses; | ||||
| 	*response = rarray; | ||||
|  | ||||
|       out: | ||||
| 	dm_free(retbuf); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| /* Free reply array */ | ||||
| static int _cluster_free_request(lvm_response_t * response, int num) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < num; i++) { | ||||
| 		dm_free(response[i].response); | ||||
| 	} | ||||
|  | ||||
| 	dm_free(response); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int refresh_clvmd(int all_nodes) | ||||
| { | ||||
| 	int num_responses; | ||||
| 	char args[1]; // No args really. | ||||
| 	lvm_response_t *response = NULL; | ||||
| 	int saved_errno; | ||||
| 	int status; | ||||
| 	int i; | ||||
|  | ||||
| 	status = _cluster_request(CLVMD_CMD_REFRESH, all_nodes ? NODE_ALL : NODE_LOCAL, args, 0, &response, &num_responses, 0); | ||||
|  | ||||
| 	/* If any nodes were down then display them and return an error */ | ||||
| 	for (i = 0; i < num_responses; i++) { | ||||
| 		if (response[i].status == EHOSTDOWN) { | ||||
| 			fprintf(stderr, "clvmd not running on node %s", | ||||
| 				  response[i].node); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} else if (response[i].status) { | ||||
| 			fprintf(stderr, "Error resetting node %s: %s", | ||||
| 				  response[i].node, | ||||
| 				  response[i].response[0] ? | ||||
| 				  	response[i].response : | ||||
| 				  	strerror(response[i].status)); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	saved_errno = errno; | ||||
| 	_cluster_free_request(response, num_responses); | ||||
| 	errno = saved_errno; | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| int restart_clvmd(int all_nodes) | ||||
| { | ||||
| 	int dummy, status; | ||||
|  | ||||
| 	status = _cluster_request(CLVMD_CMD_RESTART, all_nodes ? NODE_ALL : NODE_LOCAL, NULL, 0, NULL, &dummy, 1); | ||||
|  | ||||
| 	/* | ||||
| 	 * FIXME: we cannot receive response, clvmd re-exec before it. | ||||
| 	 *        but also should not close socket too early (the whole rq is dropped then). | ||||
| 	 * FIXME: This should be handled this way: | ||||
| 	 *  - client waits for RESTART ack (and socket close) | ||||
| 	 *  - server restarts | ||||
| 	 *  - client checks that server is ready again (VERSION command?) | ||||
| 	 */ | ||||
| 	usleep(500000); | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| int debug_clvmd(int level, int clusterwide) | ||||
| { | ||||
| 	int num_responses; | ||||
| 	char args[1]; | ||||
| 	const char *nodes; | ||||
| 	lvm_response_t *response = NULL; | ||||
| 	int saved_errno; | ||||
| 	int status; | ||||
| 	int i; | ||||
|  | ||||
| 	args[0] = level; | ||||
| 	if (clusterwide) | ||||
| 		nodes = NODE_ALL; | ||||
| 	else | ||||
| 		nodes = NODE_LOCAL; | ||||
|  | ||||
| 	status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses, 0); | ||||
|  | ||||
| 	/* If any nodes were down then display them and return an error */ | ||||
| 	for (i = 0; i < num_responses; i++) { | ||||
| 		if (response[i].status == EHOSTDOWN) { | ||||
| 			fprintf(stderr, "clvmd not running on node %s", | ||||
| 				  response[i].node); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} else if (response[i].status) { | ||||
| 			fprintf(stderr, "Error setting debug on node %s: %s", | ||||
| 				  response[i].node, | ||||
| 				  response[i].response[0] ? | ||||
| 				  	response[i].response : | ||||
| 				  	strerror(response[i].status)); | ||||
| 			status = 0; | ||||
| 			errno = response[i].status; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	saved_errno = errno; | ||||
| 	_cluster_free_request(response, num_responses); | ||||
| 	errno = saved_errno; | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
| @@ -1,39 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2009-2010 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CPG_LIBS = @CPG_LIBS@ | ||||
| CPG_CFLAGS = @CPG_CFLAGS@ | ||||
| SACKPT_LIBS = @SACKPT_LIBS@ | ||||
| SACKPT_CFLAGS = @SACKPT_CFLAGS@ | ||||
|  | ||||
| SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c | ||||
|  | ||||
| TARGETS = cmirrord | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LIBS += -ldevmapper | ||||
| LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS) | ||||
| CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS) | ||||
| LDFLAGS += $(EXTRA_EXEC_LDFLAGS) | ||||
|  | ||||
| cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a | ||||
| 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \ | ||||
| 		$(LVMLIBS) $(LMLIBS) $(LIBS) | ||||
|  | ||||
| install: $(TARGETS) | ||||
| 	$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord | ||||
| @@ -1,256 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v.2. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "common.h" | ||||
| #include "functions.h" | ||||
| #include "link_mon.h" | ||||
| #include "local.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| static volatile sig_atomic_t exit_now = 0; | ||||
| /* FIXME Review signal handling.  Should be volatile sig_atomic_t */ | ||||
| static sigset_t signal_mask; | ||||
| static volatile sig_atomic_t signal_received; | ||||
|  | ||||
| static void process_signals(void); | ||||
| static void daemonize(void); | ||||
| static void init_all(void); | ||||
| static void cleanup_all(void); | ||||
|  | ||||
| int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) | ||||
| { | ||||
| 	daemonize(); | ||||
|  | ||||
| 	init_all(); | ||||
|  | ||||
| 	/* Parent can now exit, we're ready to handle requests */ | ||||
| 	kill(getppid(), SIGTERM); | ||||
|  | ||||
| 	LOG_PRINT("Starting cmirrord:"); | ||||
| 	LOG_PRINT(" Built: "__DATE__" "__TIME__"\n"); | ||||
| 	LOG_DBG(" Compiled with debugging."); | ||||
|  | ||||
| 	while (!exit_now) { | ||||
| 		links_monitor(); | ||||
|  | ||||
| 		links_issue_callbacks(); | ||||
|  | ||||
| 		process_signals(); | ||||
| 	} | ||||
| 	exit(EXIT_SUCCESS); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * parent_exit_handler: exit the parent | ||||
|  * @sig: the signal | ||||
|  * | ||||
|  */ | ||||
| static void parent_exit_handler(int sig __attribute__((unused))) | ||||
| { | ||||
| 	exit_now = 1; | ||||
| } | ||||
|  | ||||
| static void sig_handler(int sig) | ||||
| { | ||||
| 	/* FIXME Races - don't touch signal_mask here. */ | ||||
| 	sigaddset(&signal_mask, sig); | ||||
| 	signal_received = 1; | ||||
| } | ||||
|  | ||||
| static void process_signal(int sig){ | ||||
| 	int r = 0; | ||||
|  | ||||
| 	switch(sig) { | ||||
| 	case SIGINT: | ||||
| 	case SIGQUIT: | ||||
| 	case SIGTERM: | ||||
| 	case SIGHUP: | ||||
| 		r += log_status(); | ||||
| 		break; | ||||
| 	case SIGUSR1: | ||||
| 	case SIGUSR2: | ||||
| 		log_debug(); | ||||
| 		/*local_debug();*/ | ||||
| 		cluster_debug(); | ||||
| 		return; | ||||
| 	default: | ||||
| 		LOG_PRINT("Unknown signal received... ignoring"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (!r) { | ||||
| 		LOG_DBG("No current cluster logs... safe to exit."); | ||||
| 		cleanup_all(); | ||||
| 		exit(EXIT_SUCCESS); | ||||
| 	} | ||||
|  | ||||
| 	LOG_ERROR("Cluster logs exist.  Refusing to exit."); | ||||
| } | ||||
|  | ||||
| static void process_signals(void) | ||||
| { | ||||
| 	int x; | ||||
|  | ||||
| 	if (!signal_received) | ||||
| 		return; | ||||
|  | ||||
| 	signal_received = 0; | ||||
|  | ||||
| 	for (x = 1; x < _NSIG; x++) { | ||||
| 		if (sigismember(&signal_mask, x)) { | ||||
| 			sigdelset(&signal_mask, x); | ||||
| 			process_signal(x); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void remove_lockfile(void) | ||||
| { | ||||
| 	if (unlink(CMIRRORD_PIDFILE)) | ||||
| 		LOG_ERROR("Unable to remove \"" CMIRRORD_PIDFILE "\" %s", strerror(errno)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * daemonize | ||||
|  * | ||||
|  * Performs the steps necessary to become a daemon. | ||||
|  */ | ||||
| static void daemonize(void) | ||||
| { | ||||
| 	int pid; | ||||
| 	int status; | ||||
| 	int devnull; | ||||
|  | ||||
| 	if ((devnull = open("/dev/null", O_RDWR)) == -1) { | ||||
| 		LOG_ERROR("Can't open /dev/null: %s", strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	signal(SIGTERM, &parent_exit_handler); | ||||
|  | ||||
| 	pid = fork(); | ||||
|  | ||||
| 	if (pid < 0) { | ||||
| 		LOG_ERROR("Unable to fork()"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	if (pid) { | ||||
| 		/* Parent waits here for child to get going */ | ||||
| 		while (!waitpid(pid, &status, WNOHANG) && !exit_now); | ||||
| 		if (exit_now) | ||||
| 			exit(EXIT_SUCCESS); | ||||
|  | ||||
| 		switch (WEXITSTATUS(status)) { | ||||
| 		case EXIT_LOCKFILE: | ||||
| 			LOG_ERROR("Failed to create lockfile"); | ||||
| 			LOG_ERROR("Process already running?"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_SOCKET: | ||||
| 			LOG_ERROR("Unable to create netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_BIND: | ||||
| 			LOG_ERROR("Unable to bind to netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_KERNEL_SETSOCKOPT: | ||||
| 			LOG_ERROR("Unable to setsockopt on netlink socket"); | ||||
| 			break; | ||||
| 		case EXIT_CLUSTER_CKPT_INIT: | ||||
| 			LOG_ERROR("Unable to initialize checkpoint service"); | ||||
| 			LOG_ERROR("Has the cluster infrastructure been started?"); | ||||
| 			break; | ||||
| 		case EXIT_FAILURE: | ||||
| 			LOG_ERROR("Failed to start: Generic error"); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Failed to start: Unknown error"); | ||||
| 			break; | ||||
| 		} | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	setsid(); | ||||
| 	if (chdir("/")) { | ||||
| 		LOG_ERROR("Failed to chdir /: %s", strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	umask(0); | ||||
|  | ||||
| 	if (close(0) || close(1) || close(2)) { | ||||
| 		LOG_ERROR("Failed to close terminal FDs"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	if ((dup2(devnull, 0) < 0) || /* reopen stdin */ | ||||
| 	    (dup2(devnull, 1) < 0) || /* reopen stdout */ | ||||
| 	    (dup2(devnull, 2) < 0))   /* reopen stderr */ | ||||
| 		exit(EXIT_FAILURE); | ||||
|  | ||||
| 	if ((devnull > STDERR_FILENO) && close(devnull)) { | ||||
| 		LOG_ERROR("Failed to close descriptor %d: %s", | ||||
| 			  devnull, strerror(errno)); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON); | ||||
|  | ||||
| 	(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG); | ||||
| 	if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0) | ||||
| 		exit(EXIT_LOCKFILE); | ||||
| 	(void) dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	atexit(remove_lockfile); | ||||
|  | ||||
| 	/* FIXME Replace with sigaction. (deprecated) */ | ||||
| 	signal(SIGINT, &sig_handler); | ||||
| 	signal(SIGQUIT, &sig_handler); | ||||
| 	signal(SIGTERM, &sig_handler); | ||||
| 	signal(SIGHUP, &sig_handler); | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
| 	signal(SIGUSR1, &sig_handler); | ||||
| 	signal(SIGUSR2, &sig_handler); | ||||
| 	sigemptyset(&signal_mask); | ||||
| 	signal_received = 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * init_all | ||||
|  * | ||||
|  * Initialize modules.  Exit on failure. | ||||
|  */ | ||||
| static void init_all(void) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	if ((r = init_local()) || | ||||
| 	    (r = init_cluster())) { | ||||
| 		exit(r); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * cleanup_all | ||||
|  * | ||||
|  * Clean up before exiting | ||||
|  */ | ||||
| static void cleanup_all(void) | ||||
| { | ||||
| 	cleanup_local(); | ||||
| 	cleanup_cluster(); | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,76 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_CLUSTER_H | ||||
| #define _LVM_CLOG_CLUSTER_H | ||||
|  | ||||
| #include "dm-log-userspace.h" | ||||
| #include "libdevmapper.h" | ||||
|  | ||||
| #define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */ | ||||
| #define DM_ULOG_CHECKPOINT_READY 21 | ||||
| #define DM_ULOG_MEMBER_JOIN      22 | ||||
|  | ||||
| /* | ||||
|  * There is other information in addition to what can | ||||
|  * be found in the dm_ulog_request structure that we | ||||
|  * need for processing.  'clog_request' is the wrapping | ||||
|  * structure we use to make the additional fields | ||||
|  * available. | ||||
|  */ | ||||
| struct clog_request { | ||||
| 	/* | ||||
| 	 * If we don't use a union, the structure size will | ||||
| 	 * vary between 32-bit and 64-bit machines.  So, we | ||||
| 	 * pack two 64-bit version numbers in there to force | ||||
| 	 * the size of the structure to be the same. | ||||
| 	 * | ||||
| 	 * The two version numbers also help us with endian | ||||
| 	 * issues.  The first is always little endian, while | ||||
| 	 * the second is in native format of the sending | ||||
| 	 * machine.  If the two are equal, there is no need | ||||
| 	 * to do endian conversions. | ||||
| 	 */ | ||||
| 	union { | ||||
| 		uint64_t version[2]; /* LE version and native version */ | ||||
| 		struct dm_list list; | ||||
| 	} u; | ||||
|  | ||||
| 	/* | ||||
| 	 * 'originator' is the machine from which the requests | ||||
| 	 * was made. | ||||
| 	 */ | ||||
| 	uint32_t originator; | ||||
|  | ||||
| 	/* | ||||
| 	 * 'pit_server' is the "point-in-time" server for the | ||||
| 	 * request.  (I.e.  The machine that was the server at | ||||
| 	 * the time the request was issued - only important during | ||||
| 	 * startup. | ||||
| 	 */ | ||||
| 	uint32_t pit_server; | ||||
|  | ||||
| 	/* | ||||
| 	 * The request from the kernel that is being processed | ||||
| 	 */ | ||||
| 	struct dm_ulog_request u_rq; | ||||
| }; | ||||
|  | ||||
| int init_cluster(void); | ||||
| void cleanup_cluster(void); | ||||
| void cluster_debug(void); | ||||
|  | ||||
| int create_cluster_cpg(char *uuid, uint64_t luid); | ||||
| int destroy_cluster_cpg(char *uuid); | ||||
|  | ||||
| int cluster_send(struct clog_request *rq); | ||||
|  | ||||
| #endif /* _LVM_CLOG_CLUSTER_H */ | ||||
| @@ -1,33 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_COMMON_H | ||||
| #define _LVM_CLOG_COMMON_H | ||||
|  | ||||
| /* | ||||
|  * If there are problems when forking off to become a daemon, | ||||
|  * the child will exist with one of these codes.  This allows | ||||
|  * the parent to know the reason for the failure and print it | ||||
|  * to the launching terminal. | ||||
|  * | ||||
|  * #define EXIT_SUCCESS 0 (from stdlib.h) | ||||
|  * #define EXIT_FAILURE 1 (from stdlib.h) | ||||
|  */ | ||||
| #define EXIT_LOCKFILE              2 | ||||
| #define EXIT_KERNEL_SOCKET         3 /* Failed netlink socket create */ | ||||
| #define EXIT_KERNEL_BIND           4 | ||||
| #define EXIT_KERNEL_SETSOCKOPT     5 | ||||
| #define EXIT_CLUSTER_CKPT_INIT     6 /* Failed to init checkpoint */ | ||||
| #define EXIT_QUEUE_NOMEM           7 | ||||
|  | ||||
| #define DM_ULOG_REQUEST_SIZE 1024 | ||||
|  | ||||
| #endif /* _LVM_CLOG_COMMON_H */ | ||||
| @@ -1,211 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "cluster.h" | ||||
| #include "compat.h" | ||||
| #include "xlate.h" | ||||
|  | ||||
| #include <errno.h> | ||||
|  | ||||
| /* | ||||
|  * Older versions of the log daemon communicate with different | ||||
|  * versions of the inter-machine communication structure, which | ||||
|  * varies in size and fields.  The older versions append the | ||||
|  * standard upstream version of the structure to every request. | ||||
|  * COMPAT_OFFSET is where the upstream structure starts. | ||||
|  */ | ||||
| #define COMPAT_OFFSET 256 | ||||
|  | ||||
| static void v5_data_endian_switch(struct clog_request *rq, int to_network __attribute__((unused))) | ||||
| { | ||||
| 	int i, end; | ||||
| 	int64_t *pi64; | ||||
| 	uint64_t *pu64; | ||||
| 	uint32_t rq_type = rq->u_rq.request_type & ~DM_ULOG_RESPONSE; | ||||
|  | ||||
| 	if (rq->u_rq.request_type & DM_ULOG_RESPONSE) { | ||||
| 		switch (rq_type) { | ||||
| 		case DM_ULOG_CTR: | ||||
| 		case DM_ULOG_DTR: | ||||
| 			LOG_ERROR("Invalid response type in endian switch"); | ||||
| 			exit(EXIT_FAILURE); | ||||
|  | ||||
| 		case DM_ULOG_PRESUSPEND: | ||||
| 		case DM_ULOG_POSTSUSPEND: | ||||
| 		case DM_ULOG_RESUME: | ||||
| 		case DM_ULOG_FLUSH: | ||||
| 		case DM_ULOG_MARK_REGION: | ||||
| 		case DM_ULOG_CLEAR_REGION: | ||||
| 		case DM_ULOG_SET_REGION_SYNC: | ||||
| 		case DM_ULOG_CHECKPOINT_READY: | ||||
| 		case DM_ULOG_MEMBER_JOIN: | ||||
| 		case DM_ULOG_STATUS_INFO: | ||||
| 		case DM_ULOG_STATUS_TABLE: | ||||
| 			/* No outbound data */ | ||||
| 			break; | ||||
|  | ||||
| 		case DM_ULOG_GET_REGION_SIZE: | ||||
| 		case DM_ULOG_GET_SYNC_COUNT: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		case DM_ULOG_IS_CLEAN: | ||||
| 		case DM_ULOG_IN_SYNC: | ||||
| 			pi64 = (int64_t *)rq->u_rq.data; | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			break; | ||||
| 		case DM_ULOG_GET_RESYNC_WORK: | ||||
| 		case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 			pi64 = (int64_t *)rq->u_rq.data; | ||||
| 			pu64 = ((uint64_t *)rq->u_rq.data) + 1; | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Unknown request type, %u", rq_type); | ||||
| 			return; | ||||
| 		} | ||||
| 	} else { | ||||
| 		switch (rq_type) { | ||||
| 		case DM_ULOG_CTR: | ||||
| 		case DM_ULOG_DTR: | ||||
| 			LOG_ERROR("Invalid request type in endian switch"); | ||||
| 			exit(EXIT_FAILURE); | ||||
|  | ||||
| 		case DM_ULOG_PRESUSPEND: | ||||
| 		case DM_ULOG_POSTSUSPEND: | ||||
| 		case DM_ULOG_RESUME: | ||||
| 		case DM_ULOG_GET_REGION_SIZE: | ||||
| 		case DM_ULOG_FLUSH: | ||||
| 		case DM_ULOG_GET_RESYNC_WORK: | ||||
| 		case DM_ULOG_GET_SYNC_COUNT: | ||||
| 		case DM_ULOG_STATUS_INFO: | ||||
| 		case DM_ULOG_STATUS_TABLE: | ||||
| 		case DM_ULOG_CHECKPOINT_READY: | ||||
| 		case DM_ULOG_MEMBER_JOIN: | ||||
| 			/* No incoming data */ | ||||
| 			break; | ||||
| 		case DM_ULOG_IS_CLEAN: | ||||
| 		case DM_ULOG_IN_SYNC: | ||||
| 		case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			break; | ||||
| 		case DM_ULOG_MARK_REGION: | ||||
| 		case DM_ULOG_CLEAR_REGION: | ||||
| 			end = rq->u_rq.data_size/sizeof(uint64_t); | ||||
|  | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			for (i = 0; i < end; i++) | ||||
| 				pu64[i] = xlate64(pu64[i]); | ||||
| 			break; | ||||
| 		case DM_ULOG_SET_REGION_SYNC: | ||||
| 			pu64 = (uint64_t *)rq->u_rq.data; | ||||
| 			pi64 = ((int64_t *)rq->u_rq.data) + 1; | ||||
| 			*pu64 = xlate64(*pu64); | ||||
| 			*pi64 = xlate64(*pi64); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOG_ERROR("Unknown request type, %u", rq_type); | ||||
| 			exit(EXIT_FAILURE); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int v5_endian_to_network(struct clog_request *rq) | ||||
| { | ||||
| 	int size; | ||||
| 	struct dm_ulog_request *u_rq = &rq->u_rq; | ||||
|  | ||||
| 	size = sizeof(*rq) + u_rq->data_size; | ||||
|  | ||||
| 	u_rq->error = xlate32(u_rq->error); | ||||
| 	u_rq->seq = xlate32(u_rq->seq); | ||||
|  | ||||
| 	rq->originator = xlate32(rq->originator); | ||||
|  | ||||
| 	v5_data_endian_switch(rq, 1); | ||||
|  | ||||
| 	u_rq->request_type = xlate32(u_rq->request_type); | ||||
| 	u_rq->data_size = xlate32(u_rq->data_size); | ||||
|  | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| int clog_request_to_network(struct clog_request *rq) | ||||
| { | ||||
| 	int r; | ||||
|  | ||||
| 	/* FIXME: Remove this safety check */ | ||||
| 	if (rq->u.version[0] != xlate64(rq->u.version[1])) { | ||||
| 		LOG_ERROR("Programmer error:  version[0] must be LE"); | ||||
| 		exit(EXIT_FAILURE); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Are we already running in the endian mode we send | ||||
| 	 * over the wire? | ||||
| 	 */ | ||||
| 	if (rq->u.version[0] == rq->u.version[1]) | ||||
| 		return 0; | ||||
|  | ||||
| 	r = v5_endian_to_network(rq); | ||||
| 	if (r < 0) | ||||
| 		return r; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int v5_endian_from_network(struct clog_request *rq) | ||||
| { | ||||
| 	int size; | ||||
| 	struct dm_ulog_request *u_rq = &rq->u_rq; | ||||
|  | ||||
| 	u_rq->error = xlate32(u_rq->error); | ||||
| 	u_rq->seq = xlate32(u_rq->seq); | ||||
| 	u_rq->request_type = xlate32(u_rq->request_type); | ||||
| 	u_rq->data_size = xlate32(u_rq->data_size); | ||||
|  | ||||
| 	rq->originator = xlate32(rq->originator); | ||||
|  | ||||
| 	size = sizeof(*rq) + u_rq->data_size; | ||||
|  | ||||
| 	v5_data_endian_switch(rq, 0); | ||||
|  | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| int clog_request_from_network(void *data, size_t data_len) | ||||
| { | ||||
| 	uint64_t *vp = data; | ||||
| 	uint64_t version = xlate64(vp[0]); | ||||
| 	uint64_t unconverted_version = vp[1]; | ||||
| 	struct clog_request *rq = data; | ||||
|  | ||||
| 	switch (version) { | ||||
| 	case 5: /* Upstream */ | ||||
| 		if (version == vp[0]) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case 4: /* RHEL 5.[45] */ | ||||
| 	case 3: /* RHEL 5.3 */ | ||||
| 	case 2: /* RHEL 5.2 */ | ||||
| 		/* FIXME: still need to account for payload */ | ||||
| 		if (data_len < (COMPAT_OFFSET + sizeof(*rq))) | ||||
| 			return -ENOSPC; | ||||
|  | ||||
| 		rq = (struct clog_request *)((char *)data + COMPAT_OFFSET); | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Unable to process cluster message: " | ||||
| 			  "Incompatible version"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	v5_endian_from_network(rq); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_COMPAT_H | ||||
| #define _LVM_CLOG_COMPAT_H | ||||
|  | ||||
| /* | ||||
|  * The intermachine communication structure version are: | ||||
|  *	0: Unused | ||||
|  *	1: Never in the wild | ||||
|  *	2: RHEL 5.2 | ||||
|  *	3: RHEL 5.3 | ||||
|  *	4: RHEL 5.4, RHEL 5.5 | ||||
|  *	5: RHEL 6, Current Upstream Format | ||||
|  */ | ||||
| #define CLOG_TFR_VERSION 5 | ||||
|  | ||||
| int clog_request_to_network(struct clog_request *rq); | ||||
| int clog_request_from_network(void *data, size_t data_len); | ||||
|  | ||||
| #endif /* _LVM_CLOG_COMPAT_H */ | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,34 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_FUNCTIONS_H | ||||
| #define _LVM_CLOG_FUNCTIONS_H | ||||
|  | ||||
| #include "dm-log-userspace.h" | ||||
| #include "cluster.h" | ||||
|  | ||||
| #define LOG_RESUMED   1 | ||||
| #define LOG_SUSPENDED 2 | ||||
|  | ||||
| int local_resume(struct dm_ulog_request *rq); | ||||
| int cluster_postsuspend(char *, uint64_t); | ||||
|  | ||||
| int do_request(struct clog_request *rq, int server); | ||||
| int push_state(const char *uuid, uint64_t luid, | ||||
| 	       const char *which, char **buf, uint32_t debug_who); | ||||
| int pull_state(const char *uuid, uint64_t luid, | ||||
| 	       const char *which, char *buf, int size); | ||||
|  | ||||
| int log_get_state(struct dm_ulog_request *rq); | ||||
| int log_status(void); | ||||
| void log_debug(void); | ||||
|  | ||||
| #endif /* _LVM_CLOG_FUNCTIONS_H */ | ||||
| @@ -1,151 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "link_mon.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <poll.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| struct link_callback { | ||||
| 	int fd; | ||||
| 	const char *name; | ||||
| 	void *data; | ||||
| 	int (*callback)(void *data); | ||||
|  | ||||
| 	struct link_callback *next; | ||||
| }; | ||||
|  | ||||
| static unsigned used_pfds = 0; | ||||
| static unsigned free_pfds = 0; | ||||
| static struct pollfd *pfds = NULL; | ||||
| static struct link_callback *callbacks = NULL; | ||||
|  | ||||
| int links_register(int fd, const char *name, int (*callback)(void *data), void *data) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *lc; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) { | ||||
| 		if (fd == pfds[i].fd) { | ||||
| 			LOG_ERROR("links_register: Duplicate file descriptor"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	lc = malloc(sizeof(*lc)); | ||||
| 	if (!lc) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	lc->fd = fd; | ||||
| 	lc->name = name; | ||||
| 	lc->data = data; | ||||
| 	lc->callback = callback; | ||||
|  | ||||
| 	if (!free_pfds) { | ||||
| 		struct pollfd *tmp; | ||||
| 		tmp = realloc(pfds, sizeof(struct pollfd) * ((used_pfds*2) + 1)); | ||||
| 		if (!tmp) { | ||||
| 			free(lc); | ||||
| 			return -ENOMEM; | ||||
| 		} | ||||
|  | ||||
| 		pfds = tmp; | ||||
| 		free_pfds = used_pfds + 1; | ||||
| 	} | ||||
|  | ||||
| 	free_pfds--; | ||||
| 	pfds[used_pfds].fd = fd; | ||||
| 	pfds[used_pfds].events = POLLIN; | ||||
| 	pfds[used_pfds].revents = 0; | ||||
| 	used_pfds++; | ||||
|  | ||||
| 	lc->next = callbacks; | ||||
| 	callbacks = lc; | ||||
| 	LOG_DBG("Adding %s/%d", lc->name, lc->fd); | ||||
| 	LOG_DBG(" used_pfds = %u, free_pfds = %u", | ||||
| 		used_pfds, free_pfds); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int links_unregister(int fd) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *p, *c; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (fd == pfds[i].fd) { | ||||
| 			/* entire struct is copied (overwritten) */ | ||||
| 			pfds[i] = pfds[used_pfds - 1]; | ||||
| 			used_pfds--; | ||||
| 			free_pfds++; | ||||
| 		} | ||||
|  | ||||
| 	for (p = NULL, c = callbacks; c; p = c, c = c->next) | ||||
| 		if (fd == c->fd) { | ||||
| 			LOG_DBG("Freeing up %s/%d", c->name, c->fd); | ||||
| 			LOG_DBG(" used_pfds = %u, free_pfds = %u", | ||||
| 				used_pfds, free_pfds); | ||||
| 			if (p) | ||||
| 				p->next = c->next; | ||||
| 			else | ||||
| 				callbacks = c->next; | ||||
| 			free(c); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int links_monitor(void) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	int r; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) { | ||||
| 		pfds[i].revents = 0; | ||||
| 	} | ||||
|  | ||||
| 	r = poll(pfds, used_pfds, -1); | ||||
| 	if (r <= 0) | ||||
| 		return r; | ||||
|  | ||||
| 	r = 0; | ||||
| 	/* FIXME: handle POLLHUP */ | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (pfds[i].revents & POLLIN) { | ||||
| 			LOG_DBG("Data ready on %d", pfds[i].fd); | ||||
|  | ||||
| 			/* FIXME: Add this back return 1;*/ | ||||
| 			r++; | ||||
| 		} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int links_issue_callbacks(void) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct link_callback *lc; | ||||
|  | ||||
| 	for (i = 0; i < used_pfds; i++) | ||||
| 		if (pfds[i].revents & POLLIN) | ||||
| 			for (lc = callbacks; lc; lc = lc->next) | ||||
| 				if (pfds[i].fd == lc->fd) { | ||||
| 					LOG_DBG("Issuing callback on %s/%d", | ||||
| 						lc->name, lc->fd); | ||||
| 					lc->callback(lc->data); | ||||
| 					break; | ||||
| 				} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_LINK_MON_H | ||||
| #define _LVM_CLOG_LINK_MON_H | ||||
|  | ||||
| int links_register(int fd, const char *name, int (*callback)(void *data), void *data); | ||||
| int links_unregister(int fd); | ||||
| int links_monitor(void); | ||||
| int links_issue_callbacks(void); | ||||
|  | ||||
| #endif /* _LVM_CLOG_LINK_MON_H */ | ||||
| @@ -1,424 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
| #include "common.h" | ||||
| #include "functions.h" | ||||
| #include "link_mon.h" | ||||
| #include "local.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <sys/socket.h> | ||||
| #include <linux/connector.h> | ||||
| #include <linux/netlink.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #ifndef CN_IDX_DM | ||||
| /* Kernel 2.6.31 is required to run this code */ | ||||
| #define CN_IDX_DM                       0x7     /* Device Mapper */ | ||||
| #define CN_VAL_DM_USERSPACE_LOG         0x1 | ||||
| #endif | ||||
|  | ||||
| static int cn_fd = -1;  /* Connector (netlink) socket fd */ | ||||
| static char recv_buf[2048]; | ||||
| static char send_buf[2048]; | ||||
|  | ||||
|  | ||||
| /* FIXME: merge this function with kernel_send_helper */ | ||||
| static int kernel_ack(uint32_t seq, int error) | ||||
| { | ||||
| 	int r; | ||||
| 	struct nlmsghdr *nlh = (struct nlmsghdr *)send_buf; | ||||
| 	struct cn_msg *msg = NLMSG_DATA(nlh); | ||||
|  | ||||
| 	if (error < 0) { | ||||
| 		LOG_ERROR("Programmer error: error codes must be positive"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	memset(send_buf, 0, sizeof(send_buf)); | ||||
|  | ||||
| 	nlh->nlmsg_seq = 0; | ||||
| 	nlh->nlmsg_pid = getpid(); | ||||
| 	nlh->nlmsg_type = NLMSG_DONE; | ||||
| 	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct cn_msg)); | ||||
| 	nlh->nlmsg_flags = 0; | ||||
|  | ||||
| 	msg->len = 0; | ||||
| 	msg->id.idx = CN_IDX_DM; | ||||
| 	msg->id.val = CN_VAL_DM_USERSPACE_LOG; | ||||
| 	msg->seq = seq; | ||||
| 	msg->ack = error; | ||||
|  | ||||
| 	r = send(cn_fd, nlh, NLMSG_LENGTH(sizeof(struct cn_msg)), 0); | ||||
| 	/* FIXME: do better error processing */ | ||||
| 	if (r <= 0) | ||||
| 		return -EBADE; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * kernel_recv | ||||
|  * @rq: the newly allocated request from kernel | ||||
|  * | ||||
|  * Read requests from the kernel and allocate space for the new request. | ||||
|  * If there is no request from the kernel, *rq is NULL. | ||||
|  * | ||||
|  * This function is not thread safe due to returned stack pointer.  In fact, | ||||
|  * the returned pointer must not be in-use when this function is called again. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on error | ||||
|  */ | ||||
| static int kernel_recv(struct clog_request **rq) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	ssize_t len; | ||||
| 	char *foo; | ||||
| 	struct cn_msg *msg; | ||||
| 	struct dm_ulog_request *u_rq; | ||||
| 	struct nlmsghdr *nlmsg_h; | ||||
|  | ||||
| 	*rq = NULL; | ||||
| 	memset(recv_buf, 0, sizeof(recv_buf)); | ||||
|  | ||||
| 	len = recv(cn_fd, recv_buf, sizeof(recv_buf), 0); | ||||
| 	if (len < 0) { | ||||
| 		LOG_ERROR("Failed to recv message from kernel"); | ||||
| 		r = -errno; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	nlmsg_h = (struct nlmsghdr *)recv_buf; | ||||
| 	switch (nlmsg_h->nlmsg_type) { | ||||
| 	case NLMSG_ERROR: | ||||
| 		LOG_ERROR("Unable to recv message from kernel: NLMSG_ERROR"); | ||||
| 		r = -EBADE; | ||||
| 		goto fail; | ||||
| 	case NLMSG_DONE: | ||||
| 		msg = (struct cn_msg *)NLMSG_DATA((struct nlmsghdr *)recv_buf); | ||||
| 		len -= (ssize_t)sizeof(struct nlmsghdr); | ||||
|  | ||||
| 		if (len < (ssize_t)sizeof(struct cn_msg)) { | ||||
| 			LOG_ERROR("Incomplete request from kernel received"); | ||||
| 			r = -EBADE; | ||||
| 			goto fail; | ||||
| 		} | ||||
|  | ||||
| 		if (msg->len > DM_ULOG_REQUEST_SIZE) { | ||||
| 			LOG_ERROR("Not enough space to receive kernel request (%d/%d)", | ||||
| 				  msg->len, DM_ULOG_REQUEST_SIZE); | ||||
| 			r = -EBADE; | ||||
| 			goto fail; | ||||
| 		} | ||||
|  | ||||
| 		if (!msg->len) | ||||
| 			LOG_ERROR("Zero length message received"); | ||||
|  | ||||
| 		len -= (ssize_t)sizeof(struct cn_msg); | ||||
|  | ||||
| 		if (len < msg->len) | ||||
| 			LOG_ERROR("len = %zd, msg->len = %" PRIu16, len, msg->len); | ||||
|  | ||||
| 		msg->data[msg->len] = '\0'; /* Cleaner way to ensure this? */ | ||||
| 		u_rq = (struct dm_ulog_request *)msg->data; | ||||
|  | ||||
| 		if (!u_rq->request_type) { | ||||
| 			LOG_DBG("Bad transmission, requesting resend [%u]", | ||||
| 				msg->seq); | ||||
| 			r = -EAGAIN; | ||||
|  | ||||
| 			if (kernel_ack(msg->seq, EAGAIN)) { | ||||
| 				LOG_ERROR("Failed to NACK kernel transmission [%u]", | ||||
| 					  msg->seq); | ||||
| 				r = -EBADE; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * Now we've got sizeof(struct cn_msg) + sizeof(struct nlmsghdr) | ||||
| 		 * worth of space that precede the request structure from the | ||||
| 		 * kernel.  Since that space isn't going to be used again, we | ||||
| 		 * can take it for our purposes; rather than allocating a whole | ||||
| 		 * new structure and doing a memcpy. | ||||
| 		 * | ||||
| 		 * We should really make sure 'clog_request' doesn't grow | ||||
| 		 * beyond what is available to us, but we need only check it | ||||
| 		 * once... perhaps at compile time? | ||||
| 		 */ | ||||
| 		foo = (char *)u_rq; | ||||
| 		foo -= (sizeof(struct clog_request) - sizeof(struct dm_ulog_request)); | ||||
| 		*rq = (struct clog_request *) foo; | ||||
|  | ||||
| 		/* Clear the wrapper container fields */ | ||||
| 		memset(*rq, 0, (size_t)((char *)u_rq - (char *)(*rq))); | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Unknown nlmsg_type"); | ||||
| 		r = -EBADE; | ||||
| 	} | ||||
|  | ||||
| fail: | ||||
| 	if (r) | ||||
| 		*rq = NULL; | ||||
|  | ||||
| 	return (r == -EAGAIN) ? 0 : r; | ||||
| } | ||||
|  | ||||
| static int kernel_send_helper(void *data, uint16_t out_size) | ||||
| { | ||||
| 	int r; | ||||
| 	struct nlmsghdr *nlh; | ||||
| 	struct cn_msg *msg; | ||||
|  | ||||
| 	memset(send_buf, 0, sizeof(send_buf)); | ||||
|  | ||||
| 	nlh = (struct nlmsghdr *)send_buf; | ||||
| 	nlh->nlmsg_seq = 0;  /* FIXME: Is this used? */ | ||||
| 	nlh->nlmsg_pid = getpid(); | ||||
| 	nlh->nlmsg_type = NLMSG_DONE; | ||||
| 	nlh->nlmsg_len = NLMSG_LENGTH(out_size + sizeof(struct cn_msg)); | ||||
| 	nlh->nlmsg_flags = 0; | ||||
|  | ||||
| 	msg = NLMSG_DATA(nlh); | ||||
| 	memcpy(msg->data, data, out_size); | ||||
| 	msg->len = out_size; | ||||
| 	msg->id.idx = CN_IDX_DM; | ||||
| 	msg->id.val = CN_VAL_DM_USERSPACE_LOG; | ||||
| 	msg->seq = 0; | ||||
|  | ||||
| 	r = send(cn_fd, nlh, NLMSG_LENGTH(out_size + sizeof(struct cn_msg)), 0); | ||||
| 	/* FIXME: do better error processing */ | ||||
| 	if (r <= 0) | ||||
| 		return -EBADE; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * do_local_work | ||||
|  * | ||||
|  * Any processing errors are placed in the 'rq' | ||||
|  * structure to be reported back to the kernel. | ||||
|  * It may be pointless for this function to | ||||
|  * return an int. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on failure | ||||
|  */ | ||||
| static int do_local_work(void *data __attribute__((unused))) | ||||
| { | ||||
| 	int r; | ||||
| 	struct clog_request *rq; | ||||
| 	struct dm_ulog_request *u_rq = NULL; | ||||
|  | ||||
| 	r = kernel_recv(&rq); | ||||
| 	if (r) | ||||
| 		return r; | ||||
|  | ||||
| 	if (!rq) | ||||
| 		return 0; | ||||
|  | ||||
| 	u_rq = &rq->u_rq; | ||||
| 	LOG_DBG("[%s]  Request from kernel received: [%s/%u]", | ||||
| 		SHORT_UUID(u_rq->uuid), RQ_TYPE(u_rq->request_type), | ||||
| 		u_rq->seq); | ||||
| 	switch (u_rq->request_type) { | ||||
| 	case DM_ULOG_CTR: | ||||
| 	case DM_ULOG_DTR: | ||||
| 	case DM_ULOG_GET_REGION_SIZE: | ||||
| 	case DM_ULOG_IN_SYNC: | ||||
| 	case DM_ULOG_GET_SYNC_COUNT: | ||||
| 	case DM_ULOG_STATUS_TABLE: | ||||
| 	case DM_ULOG_PRESUSPEND: | ||||
| 		/* We do not specify ourselves as server here */ | ||||
| 		r = do_request(rq, 0); | ||||
| 		if (r) | ||||
| 			LOG_DBG("Returning failed request to kernel [%s]", | ||||
| 				RQ_TYPE(u_rq->request_type)); | ||||
| 		r = kernel_send(u_rq); | ||||
| 		if (r) | ||||
| 			LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 				  RQ_TYPE(u_rq->request_type)); | ||||
|  | ||||
| 		break; | ||||
| 	case DM_ULOG_RESUME: | ||||
| 		/* | ||||
| 		 * Resume is a special case that requires a local | ||||
| 		 * component to join the CPG, and a cluster component | ||||
| 		 * to handle the request. | ||||
| 		 */ | ||||
| 		r = local_resume(u_rq); | ||||
| 		if (r) { | ||||
| 			LOG_DBG("Returning failed request to kernel [%s]", | ||||
| 				RQ_TYPE(u_rq->request_type)); | ||||
| 			r = kernel_send(u_rq); | ||||
| 			if (r) | ||||
| 				LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 					  RQ_TYPE(u_rq->request_type)); | ||||
| 			break; | ||||
| 		} | ||||
| 		/* ELSE, fall through */ | ||||
| 	case DM_ULOG_IS_CLEAN: | ||||
| 	case DM_ULOG_FLUSH: | ||||
| 	case DM_ULOG_MARK_REGION: | ||||
| 	case DM_ULOG_GET_RESYNC_WORK: | ||||
| 	case DM_ULOG_SET_REGION_SYNC: | ||||
| 	case DM_ULOG_STATUS_INFO: | ||||
| 	case DM_ULOG_IS_REMOTE_RECOVERING: | ||||
| 	case DM_ULOG_POSTSUSPEND: | ||||
| 		r = cluster_send(rq); | ||||
| 		if (r) { | ||||
| 			u_rq->data_size = 0; | ||||
| 			u_rq->error = r; | ||||
| 			if (kernel_send(u_rq)) | ||||
| 				LOG_ERROR("Failed to respond to kernel [%s]", | ||||
| 					  RQ_TYPE(u_rq->request_type)); | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	case DM_ULOG_CLEAR_REGION: | ||||
| 		r = kernel_ack(u_rq->seq, 0); | ||||
|  | ||||
| 		r = cluster_send(rq); | ||||
| 		if (r) { | ||||
| 			/* | ||||
| 			 * FIXME: store error for delivery on flush | ||||
| 			 *        This would allow us to optimize MARK_REGION | ||||
| 			 *        too. | ||||
| 			 */ | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	default: | ||||
| 		LOG_ERROR("Invalid log request received (%u), ignoring.", | ||||
| 			  u_rq->request_type); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (r && !u_rq->error) | ||||
| 		u_rq->error = r; | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * kernel_send | ||||
|  * @u_rq: result to pass back to kernel | ||||
|  * | ||||
|  * This function returns the u_rq structure | ||||
|  * (containing the results) to the kernel. | ||||
|  * It then frees the structure. | ||||
|  * | ||||
|  * WARNING: should the structure be freed if | ||||
|  * there is an error?  I vote 'yes'.  If the | ||||
|  * kernel doesn't get the response, it should | ||||
|  * resend the request. | ||||
|  * | ||||
|  * Returns: 0 on success, -EXXX on failure | ||||
|  */ | ||||
| int kernel_send(struct dm_ulog_request *u_rq) | ||||
| { | ||||
| 	int r; | ||||
| 	uint16_t size; | ||||
|  | ||||
| 	if (!u_rq) | ||||
| 		return -EINVAL; | ||||
|  | ||||
| 	size = (uint16_t)(sizeof(struct dm_ulog_request) + u_rq->data_size); | ||||
|  | ||||
| 	if (!u_rq->data_size && !u_rq->error) { | ||||
| 		/* An ACK is all that is needed */ | ||||
|  | ||||
| 		/* FIXME: add ACK code */ | ||||
| 	} else if (size > DM_ULOG_REQUEST_SIZE) { | ||||
| 		/* | ||||
| 		 * If we gotten here, we've already overrun | ||||
| 		 * our allotted space somewhere. | ||||
| 		 * | ||||
| 		 * We must do something, because the kernel | ||||
| 		 * is waiting for a response. | ||||
| 		 */ | ||||
| 		LOG_ERROR("Not enough space to respond to server"); | ||||
| 		u_rq->error = -ENOSPC; | ||||
| 		size = sizeof(struct dm_ulog_request); | ||||
| 	} | ||||
|  | ||||
| 	r = kernel_send_helper(u_rq, size); | ||||
| 	if (r) | ||||
| 		LOG_ERROR("Failed to send msg to kernel."); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * init_local | ||||
|  * | ||||
|  * Initialize kernel communication socket (netlink) | ||||
|  * | ||||
|  * Returns: 0 on success, values from common.h on failure | ||||
|  */ | ||||
| int init_local(void) | ||||
| { | ||||
| 	int r = 0; | ||||
| 	unsigned opt; | ||||
| 	struct sockaddr_nl addr; | ||||
|  | ||||
| 	cn_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | ||||
| 	if (cn_fd < 0) | ||||
| 		return EXIT_KERNEL_SOCKET; | ||||
|  | ||||
| 	/* memset to fix valgrind complaint */ | ||||
| 	memset(&addr, 0, sizeof(struct sockaddr_nl)); | ||||
|  | ||||
| 	addr.nl_family = AF_NETLINK; | ||||
| 	addr.nl_groups = CN_IDX_DM; | ||||
| 	addr.nl_pid = 0; | ||||
|  | ||||
| 	r = bind(cn_fd, (struct sockaddr *) &addr, sizeof(addr)); | ||||
| 	if (r < 0) { | ||||
| 		if (close(cn_fd)) | ||||
| 			LOG_ERROR("Failed to close socket: %s", | ||||
| 				  strerror(errno)); | ||||
| 		return EXIT_KERNEL_BIND; | ||||
| 	} | ||||
|  | ||||
| 	opt = addr.nl_groups; | ||||
| 	r = setsockopt(cn_fd, 270, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt)); | ||||
| 	if (r) { | ||||
| 		if (close(cn_fd)) | ||||
| 			LOG_ERROR("Failed to close socket: %s", | ||||
| 				  strerror(errno)); | ||||
| 		return EXIT_KERNEL_SETSOCKOPT; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	r = fcntl(cn_fd, F_SETFL, FNDELAY); | ||||
| 	*/ | ||||
|  | ||||
| 	links_register(cn_fd, "local", do_local_work, NULL); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * cleanup_local | ||||
|  * | ||||
|  * Clean up before exiting | ||||
|  */ | ||||
| void cleanup_local(void) | ||||
| { | ||||
| 	links_unregister(cn_fd); | ||||
| 	if (cn_fd >= 0 && close(cn_fd)) | ||||
| 		LOG_ERROR("Failed to close socket: %s", | ||||
| 			  strerror(errno)); | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #ifndef _LVM_CLOG_LOCAL_H | ||||
| #define _LVM_CLOG_LOCAL_H | ||||
|  | ||||
| int init_local(void); | ||||
| void cleanup_local(void); | ||||
|  | ||||
| int kernel_send(struct dm_ulog_request *rq); | ||||
|  | ||||
| #endif /* _LVM_CLOG_LOCAL_H */ | ||||
| @@ -1,57 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
| #include "logging.h" | ||||
|  | ||||
| const char *__rq_types_off_by_one[] = { | ||||
| 	"DM_ULOG_CTR", | ||||
| 	"DM_ULOG_DTR", | ||||
| 	"DM_ULOG_PRESUSPEND", | ||||
| 	"DM_ULOG_POSTSUSPEND", | ||||
| 	"DM_ULOG_RESUME", | ||||
| 	"DM_ULOG_GET_REGION_SIZE", | ||||
| 	"DM_ULOG_IS_CLEAN", | ||||
| 	"DM_ULOG_IN_SYNC", | ||||
| 	"DM_ULOG_FLUSH", | ||||
| 	"DM_ULOG_MARK_REGION", | ||||
| 	"DM_ULOG_CLEAR_REGION", | ||||
| 	"DM_ULOG_GET_RESYNC_WORK", | ||||
| 	"DM_ULOG_SET_REGION_SYNC", | ||||
| 	"DM_ULOG_GET_SYNC_COUNT", | ||||
| 	"DM_ULOG_STATUS_INFO", | ||||
| 	"DM_ULOG_STATUS_TABLE", | ||||
| 	"DM_ULOG_IS_REMOTE_RECOVERING", | ||||
| 	NULL | ||||
| }; | ||||
|  | ||||
| int log_tabbing = 0; | ||||
| int log_is_open = 0; | ||||
|  | ||||
| /* | ||||
|  * Variables for various conditional logging | ||||
|  */ | ||||
| #ifdef MEMB | ||||
| int log_membership_change = 1; | ||||
| #else | ||||
| int log_membership_change = 0; | ||||
| #endif | ||||
|  | ||||
| #ifdef CKPT | ||||
| int log_checkpoint = 1; | ||||
| #else | ||||
| int log_checkpoint = 0; | ||||
| #endif | ||||
|  | ||||
| #ifdef RESEND | ||||
| int log_resend_requests = 1; | ||||
| #else | ||||
| int log_resend_requests = 0; | ||||
| #endif | ||||
| @@ -1,77 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_CLOG_LOGGING_H | ||||
| #define _LVM_CLOG_LOGGING_H | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include "configure.h" | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <syslog.h> | ||||
|  | ||||
| /* SHORT_UUID - print last 8 chars of a string */ | ||||
| #define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x) | ||||
|  | ||||
| extern const char *__rq_types_off_by_one[]; | ||||
| #define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1] | ||||
|  | ||||
| extern int log_tabbing; | ||||
| extern int log_is_open; | ||||
| extern int log_membership_change; | ||||
| extern int log_checkpoint; | ||||
| extern int log_resend_requests; | ||||
|  | ||||
| #define LOG_OPEN(ident, option, facility) do { \ | ||||
| 		openlog(ident, option, facility); \ | ||||
| 		log_is_open = 1;		  \ | ||||
| 	} while (0) | ||||
|  | ||||
| #define LOG_CLOSE(void) do { \ | ||||
| 		log_is_open = 0; \ | ||||
| 		closelog();	 \ | ||||
| 	} while (0) | ||||
|  | ||||
| #define LOG_OUTPUT(level, f, arg...) do {				\ | ||||
| 		int __i;						\ | ||||
| 		char __buffer[16];					\ | ||||
| 		FILE *fp = (level > LOG_NOTICE) ? stderr : stdout;	\ | ||||
| 		if (log_is_open) {					\ | ||||
| 			for (__i = 0; (__i < log_tabbing) && (__i < 15); __i++) \ | ||||
| 				__buffer[__i] = '\t';			\ | ||||
| 			__buffer[__i] = '\0';				\ | ||||
| 			syslog(level, "%s" f "\n", __buffer, ## arg);	\ | ||||
| 		} else {						\ | ||||
| 			for (__i = 0; __i < log_tabbing; __i++)		\ | ||||
| 				fprintf(fp, "\t");			\ | ||||
| 			fprintf(fp, f "\n", ## arg);			\ | ||||
| 		}							\ | ||||
| 	} while (0) | ||||
|  | ||||
|  | ||||
| #ifdef DEBUG | ||||
| #define LOG_DBG(f, arg...) LOG_OUTPUT(LOG_DEBUG, f, ## arg) | ||||
| #else /* DEBUG */ | ||||
| #define LOG_DBG(f, arg...) do {} while (0) | ||||
| #endif /* DEBUG */ | ||||
|  | ||||
| #define LOG_COND(__X, f, arg...) do {\ | ||||
| 		if (__X) { 	     \ | ||||
| 			LOG_OUTPUT(LOG_NOTICE, f, ## arg); \ | ||||
| 		} \ | ||||
| 	} while (0) | ||||
| #define LOG_PRINT(f, arg...) LOG_OUTPUT(LOG_NOTICE, f, ## arg) | ||||
| #define LOG_ERROR(f, arg...) LOG_OUTPUT(LOG_ERR, f, ## arg) | ||||
|  | ||||
| #endif /* _LVM_CLOG_LOGGING_H */ | ||||
| @@ -1,4 +0,0 @@ | ||||
| init_fifos | ||||
| fini_fifos | ||||
| daemon_talk | ||||
| dm_event_get_version | ||||
| @@ -1,110 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the device-mapper userspace tools. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU Lesser General Public License v.2.1. | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| SOURCES = libdevmapper-event.c | ||||
| SOURCES2 = dmeventd.c | ||||
|  | ||||
| TARGETS = dmeventd | ||||
|  | ||||
| .PHONY: install_lib_dynamic install_lib_static install_include \ | ||||
| 	install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \ | ||||
| 	install_lib install_dmeventd | ||||
|  | ||||
| INSTALL_DMEVENTD_TARGETS = install_dmeventd_dynamic | ||||
| INSTALL_LIB_TARGETS = install_lib_dynamic | ||||
|  | ||||
| LIB_NAME = libdevmapper-event | ||||
| ifeq ("@STATIC_LINK@", "yes") | ||||
|   LIB_STATIC = $(LIB_NAME).a | ||||
|   TARGETS += $(LIB_STATIC) dmeventd.static | ||||
|   INSTALL_DMEVENTD_TARGETS += install_dmeventd_static | ||||
|   INSTALL_LIB_TARGETS += install_lib_static | ||||
| endif | ||||
|  | ||||
| LIB_VERSION = $(LIB_VERSION_DM) | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
|  | ||||
| CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a | ||||
|  | ||||
| ifneq ($(MAKECMDGOALS),device-mapper) | ||||
|   SUBDIRS+=plugins | ||||
| endif | ||||
|  | ||||
| CFLOW_LIST = $(SOURCES) | ||||
| CFLOW_LIST_TARGET = $(LIB_NAME).cflow | ||||
| CFLOW_TARGET = dmeventd | ||||
|  | ||||
| EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h | ||||
| EXPORTED_FN_PREFIX = dm_event | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| all: device-mapper | ||||
| device-mapper: $(TARGETS) | ||||
|  | ||||
| LIBS += -ldevmapper | ||||
| LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS) | ||||
|  | ||||
| CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS) | ||||
|  | ||||
| dmeventd: $(LIB_SHARED) dmeventd.o | ||||
| 	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -L. -o $@ dmeventd.o \ | ||||
| 	$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic | ||||
|  | ||||
| dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a | ||||
| 	$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \ | ||||
| 	dmeventd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS) | ||||
|  | ||||
| ifeq ("@PKGCONFIG@", "yes") | ||||
|   INSTALL_LIB_TARGETS += install_pkgconfig | ||||
| endif | ||||
|  | ||||
| ifneq ("$(CFLOW_CMD)", "") | ||||
| CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) | ||||
| -include $(top_builddir)/libdm/libdevmapper.cflow | ||||
| -include $(top_builddir)/lib/liblvm-internal.cflow | ||||
| -include $(top_builddir)/lib/liblvm2cmd.cflow | ||||
| -include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow | ||||
| -include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow | ||||
| endif | ||||
|  | ||||
| install_include: $(srcdir)/libdevmapper-event.h | ||||
| 	$(INSTALL_DATA) -D $< $(includedir)/$(<F) | ||||
|  | ||||
| install_pkgconfig: libdevmapper-event.pc | ||||
| 	$(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc | ||||
|  | ||||
| install_lib_dynamic: install_lib_shared | ||||
|  | ||||
| install_lib_static: $(LIB_STATIC) | ||||
| 	$(INSTALL_DATA) -D $< $(usrlibdir)/$(<F) | ||||
|  | ||||
| install_lib: $(INSTALL_LIB_TARGETS) | ||||
|  | ||||
| install_dmeventd_dynamic: dmeventd | ||||
| 	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F) | ||||
|  | ||||
| install_dmeventd_static: dmeventd.static | ||||
| 	$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F) | ||||
|  | ||||
| install_dmeventd: $(INSTALL_DMEVENTD_TARGETS) | ||||
|  | ||||
| install: install_include install_lib install_dmeventd | ||||
|  | ||||
| install_device-mapper: install_include install_lib install_dmeventd | ||||
|  | ||||
| DISTCLEAN_TARGETS += libdevmapper-event.pc | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,76 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef __DMEVENTD_DOT_H__ | ||||
| #define __DMEVENTD_DOT_H__ | ||||
|  | ||||
| /* FIXME This stuff must be configurable. */ | ||||
|  | ||||
| #define	DM_EVENT_FIFO_CLIENT	DEFAULT_DM_RUN_DIR "/dmeventd-client" | ||||
| #define	DM_EVENT_FIFO_SERVER	DEFAULT_DM_RUN_DIR "/dmeventd-server" | ||||
|  | ||||
| #define DM_EVENT_DEFAULT_TIMEOUT 10 | ||||
|  | ||||
| /* Commands for the daemon passed in the message below. */ | ||||
| enum dm_event_command { | ||||
| 	DM_EVENT_CMD_ACTIVE = 1, | ||||
| 	DM_EVENT_CMD_REGISTER_FOR_EVENT, | ||||
| 	DM_EVENT_CMD_UNREGISTER_FOR_EVENT, | ||||
| 	DM_EVENT_CMD_GET_REGISTERED_DEVICE, | ||||
| 	DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE, | ||||
| 	DM_EVENT_CMD_SET_TIMEOUT, | ||||
| 	DM_EVENT_CMD_GET_TIMEOUT, | ||||
| 	DM_EVENT_CMD_HELLO, | ||||
| 	DM_EVENT_CMD_DIE, | ||||
| 	DM_EVENT_CMD_GET_STATUS, | ||||
| 	DM_EVENT_CMD_GET_PARAMETERS, | ||||
| }; | ||||
|  | ||||
| /* Message passed between client and daemon. */ | ||||
| struct dm_event_daemon_message { | ||||
| 	uint32_t cmd; | ||||
| 	uint32_t size; | ||||
| 	char *data; | ||||
| }; | ||||
|  | ||||
| /* FIXME Is this meant to be exported?  I can't see where the | ||||
|    interface uses it. */ | ||||
| /* Fifos for client/daemon communication. */ | ||||
| struct dm_event_fifos { | ||||
| 	int client; | ||||
| 	int server; | ||||
| 	const char *client_path; | ||||
| 	const char *server_path; | ||||
| }; | ||||
|  | ||||
| /*      EXIT_SUCCESS             0 -- stdlib.h */ | ||||
| /*      EXIT_FAILURE             1 -- stdlib.h */ | ||||
| /*      EXIT_LOCKFILE_INUSE      2 -- obsoleted */ | ||||
| #define EXIT_DESC_CLOSE_FAILURE  3 | ||||
| #define EXIT_DESC_OPEN_FAILURE   4 | ||||
| /*      EXIT_OPEN_PID_FAILURE    5 -- obsoleted */ | ||||
| #define EXIT_FIFO_FAILURE        6 | ||||
| #define EXIT_CHDIR_FAILURE       7 | ||||
|  | ||||
| /* Implemented in libdevmapper-event.c, but not part of public API. */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| int daemon_talk(struct dm_event_fifos *fifos, | ||||
| 		struct dm_event_daemon_message *msg, int cmd, | ||||
| 		const char *dso_name, const char *dev_name, | ||||
| 		enum dm_event_mask evmask, uint32_t timeout); | ||||
| int init_fifos(struct dm_event_fifos *fifos); | ||||
| void fini_fifos(struct dm_event_fifos *fifos); | ||||
| int dm_event_get_version(struct dm_event_fifos *fifos, int *version); | ||||
|  | ||||
| #endif /* __DMEVENTD_DOT_H__ */ | ||||
| @@ -1,875 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "dmlib.h" | ||||
| #include "libdevmapper-event.h" | ||||
| //#include "libmultilog.h" | ||||
| #include "dmeventd.h" | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sys/file.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/wait.h> | ||||
| #include <arpa/inet.h>		/* for htonl, ntohl */ | ||||
|  | ||||
| static int _sequence_nr = 0; | ||||
|  | ||||
| struct dm_event_handler { | ||||
| 	char *dso; | ||||
|  | ||||
| 	char *dmeventd_path; | ||||
|  | ||||
| 	char *dev_name; | ||||
|  | ||||
| 	char *uuid; | ||||
| 	int major; | ||||
| 	int minor; | ||||
| 	uint32_t timeout; | ||||
|  | ||||
| 	enum dm_event_mask mask; | ||||
| }; | ||||
|  | ||||
| static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	dm_free(dmevh->dev_name); | ||||
| 	dm_free(dmevh->uuid); | ||||
| 	dmevh->dev_name = dmevh->uuid = NULL; | ||||
| 	dmevh->major = dmevh->minor = 0; | ||||
| } | ||||
|  | ||||
| struct dm_event_handler *dm_event_handler_create(void) | ||||
| { | ||||
| 	struct dm_event_handler *dmevh; | ||||
|  | ||||
| 	if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) { | ||||
| 		log_error("Failed to allocate event handler."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return dmevh; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_destroy(struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
| 	dm_free(dmevh->dso); | ||||
| 	dm_free(dmevh->dmeventd_path); | ||||
| 	dm_free(dmevh); | ||||
| } | ||||
|  | ||||
| int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path) | ||||
| { | ||||
| 	if (!dmeventd_path) /* noop */ | ||||
| 		return 0; | ||||
|  | ||||
| 	dm_free(dmevh->dmeventd_path); | ||||
|  | ||||
| 	if (!(dmevh->dmeventd_path = dm_strdup(dmeventd_path))) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path) | ||||
| { | ||||
| 	if (!path) /* noop */ | ||||
| 		return 0; | ||||
|  | ||||
| 	dm_free(dmevh->dso); | ||||
|  | ||||
| 	if (!(dmevh->dso = dm_strdup(path))) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name) | ||||
| { | ||||
| 	if (!dev_name) | ||||
| 		return 0; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
|  | ||||
| 	if (!(dmevh->dev_name = dm_strdup(dev_name))) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid) | ||||
| { | ||||
| 	if (!uuid) | ||||
| 		return 0; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
|  | ||||
| 	if (!(dmevh->uuid = dm_strdup(uuid))) | ||||
| 		return -ENOMEM; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major) | ||||
| { | ||||
| 	int minor = dmevh->minor; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
|  | ||||
| 	dmevh->major = major; | ||||
| 	dmevh->minor = minor; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor) | ||||
| { | ||||
| 	int major = dmevh->major; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
|  | ||||
| 	dmevh->major = major; | ||||
| 	dmevh->minor = minor; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh, | ||||
| 				     enum dm_event_mask evmask) | ||||
| { | ||||
| 	dmevh->mask = evmask; | ||||
| } | ||||
|  | ||||
| void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout) | ||||
| { | ||||
| 	dmevh->timeout = timeout; | ||||
| } | ||||
|  | ||||
| const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->dso; | ||||
| } | ||||
|  | ||||
| const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->dev_name; | ||||
| } | ||||
|  | ||||
| const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->uuid; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_get_major(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->major; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_get_minor(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->minor; | ||||
| } | ||||
|  | ||||
| int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->timeout; | ||||
| } | ||||
|  | ||||
| enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	return dmevh->mask; | ||||
| } | ||||
|  | ||||
| static int _check_message_id(struct dm_event_daemon_message *msg) | ||||
| { | ||||
| 	int pid, seq_nr; | ||||
|  | ||||
| 	if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) || | ||||
| 	    (pid != getpid()) || (seq_nr != _sequence_nr)) { | ||||
| 		log_error("Ignoring out-of-sequence reply from dmeventd. " | ||||
| 			  "Expected %d:%d but received %s", getpid(), | ||||
| 			  _sequence_nr, msg->data); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * daemon_read | ||||
|  * @fifos | ||||
|  * @msg | ||||
|  * | ||||
|  * Read message from daemon. | ||||
|  * | ||||
|  * Returns: 0 on failure, 1 on success | ||||
|  */ | ||||
| static int _daemon_read(struct dm_event_fifos *fifos, | ||||
| 			struct dm_event_daemon_message *msg) | ||||
| { | ||||
| 	unsigned bytes = 0; | ||||
| 	int ret, i; | ||||
| 	fd_set fds; | ||||
| 	size_t size = 2 * sizeof(uint32_t);	/* status + size */ | ||||
| 	uint32_t *header = alloca(size); | ||||
| 	char *buf = (char *)header; | ||||
|  | ||||
| 	while (bytes < size) { | ||||
| 		for (i = 0, ret = 0; (i < 20) && (ret < 1); i++) { | ||||
| 			/* Watch daemon read FIFO for input. */ | ||||
| 			struct timeval tval = { .tv_sec = 1 }; | ||||
| 			FD_ZERO(&fds); | ||||
| 			FD_SET(fifos->server, &fds); | ||||
| 			ret = select(fifos->server + 1, &fds, NULL, NULL, &tval); | ||||
| 			if (ret < 0 && errno != EINTR) { | ||||
| 				log_error("Unable to read from event server"); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			if ((ret == 0) && (i > 4) && !bytes) { | ||||
| 				log_error("No input from event server."); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 		if (ret < 1) { | ||||
| 			log_error("Unable to read from event server."); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		ret = read(fifos->server, buf + bytes, size); | ||||
| 		if (ret < 0) { | ||||
| 			if ((errno == EINTR) || (errno == EAGAIN)) | ||||
| 				continue; | ||||
| 			else { | ||||
| 				log_error("Unable to read from event server."); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		bytes += ret; | ||||
| 		if (header && (bytes == 2 * sizeof(uint32_t))) { | ||||
| 			msg->cmd = ntohl(header[0]); | ||||
| 			msg->size = ntohl(header[1]); | ||||
| 			buf = msg->data = dm_malloc(msg->size); | ||||
| 			size = msg->size; | ||||
| 			bytes = 0; | ||||
| 			header = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (bytes != size) { | ||||
| 		dm_free(msg->data); | ||||
| 		msg->data = NULL; | ||||
| 	} | ||||
| 	return bytes == size; | ||||
| } | ||||
|  | ||||
| /* Write message to daemon. */ | ||||
| static int _daemon_write(struct dm_event_fifos *fifos, | ||||
| 			 struct dm_event_daemon_message *msg) | ||||
| { | ||||
| 	int ret; | ||||
| 	fd_set fds; | ||||
| 	size_t bytes = 0; | ||||
| 	size_t size = 2 * sizeof(uint32_t) + msg->size; | ||||
| 	uint32_t *header = alloca(size); | ||||
| 	char *buf = (char *)header; | ||||
| 	char drainbuf[128]; | ||||
|  | ||||
| 	header[0] = htonl(msg->cmd); | ||||
| 	header[1] = htonl(msg->size); | ||||
| 	memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size); | ||||
|  | ||||
| 	/* drain the answer fifo */ | ||||
| 	while (1) { | ||||
| 		struct timeval tval = { .tv_usec = 100 }; | ||||
| 		FD_ZERO(&fds); | ||||
| 		FD_SET(fifos->server, &fds); | ||||
| 		ret = select(fifos->server + 1, &fds, NULL, NULL, &tval); | ||||
| 		if (ret < 0) { | ||||
| 			if (errno == EINTR) | ||||
| 				continue; | ||||
| 			log_error("Unable to talk to event daemon"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (ret == 0) | ||||
| 			break; | ||||
| 		ret = read(fifos->server, drainbuf, sizeof(drainbuf)); | ||||
| 		if (ret < 0) { | ||||
| 			if ((errno == EINTR) || (errno == EAGAIN)) | ||||
| 				continue; | ||||
| 			log_error("Unable to talk to event daemon"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	while (bytes < size) { | ||||
| 		do { | ||||
| 			/* Watch daemon write FIFO to be ready for output. */ | ||||
| 			FD_ZERO(&fds); | ||||
| 			FD_SET(fifos->client, &fds); | ||||
| 			ret = select(fifos->client + 1, NULL, &fds, NULL, NULL); | ||||
| 			if ((ret < 0) && (errno != EINTR)) { | ||||
| 				log_error("Unable to talk to event daemon"); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} while (ret < 1); | ||||
|  | ||||
| 		ret = write(fifos->client, buf + bytes, size - bytes); | ||||
| 		if (ret < 0) { | ||||
| 			if ((errno == EINTR) || (errno == EAGAIN)) | ||||
| 				continue; | ||||
| 			else { | ||||
| 				log_error("Unable to talk to event daemon"); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		bytes += ret; | ||||
| 	} | ||||
|  | ||||
| 	return bytes == size; | ||||
| } | ||||
|  | ||||
| int daemon_talk(struct dm_event_fifos *fifos, | ||||
| 		struct dm_event_daemon_message *msg, int cmd, | ||||
| 		const char *dso_name, const char *dev_name, | ||||
| 		enum dm_event_mask evmask, uint32_t timeout) | ||||
| { | ||||
| 	int msg_size; | ||||
| 	memset(msg, 0, sizeof(*msg)); | ||||
|  | ||||
| 	/* | ||||
| 	 * Set command and pack the arguments | ||||
| 	 * into ASCII message string. | ||||
| 	 */ | ||||
| 	if ((msg_size = | ||||
| 	     ((cmd == DM_EVENT_CMD_HELLO) ? | ||||
| 	      dm_asprintf(&(msg->data), "%d:%d HELLO", getpid(), _sequence_nr) : | ||||
| 	      dm_asprintf(&(msg->data), "%d:%d %s %s %u %" PRIu32, | ||||
| 			  getpid(), _sequence_nr, | ||||
| 			  dso_name ? : "-", dev_name ? : "-", evmask, timeout))) | ||||
| 	    < 0) { | ||||
| 		log_error("_daemon_talk: message allocation failed"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	msg->cmd = cmd; | ||||
| 	msg->size = msg_size; | ||||
|  | ||||
| 	/* | ||||
| 	 * Write command and message to and | ||||
| 	 * read status return code from daemon. | ||||
| 	 */ | ||||
| 	if (!_daemon_write(fifos, msg)) { | ||||
| 		stack; | ||||
| 		dm_free(msg->data); | ||||
| 		msg->data = NULL; | ||||
| 		return -EIO; | ||||
| 	} | ||||
|  | ||||
| 	do { | ||||
| 		dm_free(msg->data); | ||||
| 		msg->data = NULL; | ||||
|  | ||||
| 		if (!_daemon_read(fifos, msg)) { | ||||
| 			stack; | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 	} while (!_check_message_id(msg)); | ||||
|  | ||||
| 	_sequence_nr++; | ||||
|  | ||||
| 	return (int32_t) msg->cmd; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * start_daemon | ||||
|  * | ||||
|  * This function forks off a process (dmeventd) that will handle | ||||
|  * the events.  I am currently test opening one of the fifos to | ||||
|  * ensure that the daemon is running and listening...  I thought | ||||
|  * this would be less expensive than fork/exec'ing every time. | ||||
|  * Perhaps there is an even quicker/better way (no, checking the | ||||
|  * lock file is _not_ a better way). | ||||
|  * | ||||
|  * Returns: 1 on success, 0 otherwise | ||||
|  */ | ||||
| static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	int pid, ret = 0; | ||||
| 	int status; | ||||
| 	struct stat statbuf; | ||||
| 	char default_dmeventd_path[] = DMEVENTD_PATH; | ||||
| 	char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL }; | ||||
|  | ||||
| 	if (stat(fifos->client_path, &statbuf)) | ||||
| 		goto start_server; | ||||
|  | ||||
| 	if (!S_ISFIFO(statbuf.st_mode)) { | ||||
| 		log_error("%s is not a fifo.", fifos->client_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Anyone listening?  If not, errno will be ENXIO */ | ||||
| 	fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK); | ||||
| 	if (fifos->client >= 0) { | ||||
| 		/* server is running and listening */ | ||||
| 		if (close(fifos->client)) | ||||
| 			log_sys_debug("close", fifos->client_path); | ||||
| 		return 1; | ||||
| 	} else if (errno != ENXIO) { | ||||
| 		/* problem */ | ||||
| 		log_sys_error("open", fifos->client_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|       start_server: | ||||
| 	/* server is not running */ | ||||
|  | ||||
| 	if ((args[0][0] == '/') && stat(args[0], &statbuf)) { | ||||
| 		log_sys_error("stat", args[0]); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	pid = fork(); | ||||
|  | ||||
| 	if (pid < 0) | ||||
| 		log_sys_error("fork", ""); | ||||
|  | ||||
| 	else if (!pid) { | ||||
| 		execvp(args[0], args); | ||||
| 		log_error("Unable to exec dmeventd: %s", strerror(errno)); | ||||
| 		_exit(EXIT_FAILURE); | ||||
| 	} else { | ||||
| 		if (waitpid(pid, &status, 0) < 0) | ||||
| 			log_error("Unable to start dmeventd: %s", | ||||
| 				  strerror(errno)); | ||||
| 		else if (WEXITSTATUS(status)) | ||||
| 			log_error("Unable to start dmeventd."); | ||||
| 		else | ||||
| 			ret = 1; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int init_fifos(struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	/* FIXME? Is fifo the most suitable method? Why not share | ||||
| 	   comms/daemon code with something else e.g. multipath? */ | ||||
|  | ||||
| 	/* Open the fifo used to read from the daemon. */ | ||||
| 	if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) { | ||||
| 		log_sys_error("open", fifos->server_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Lock out anyone else trying to do communication with the daemon. */ | ||||
| 	if (flock(fifos->server, LOCK_EX) < 0) { | ||||
| 		log_sys_error("flock", fifos->server_path); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| /*	if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/ | ||||
| 	if ((fifos->client = open(fifos->client_path, O_RDWR | O_NONBLOCK)) < 0) { | ||||
| 		log_sys_error("open", fifos->client_path); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| bad: | ||||
| 	if (close(fifos->server)) | ||||
| 		log_sys_debug("close", fifos->server_path); | ||||
| 	fifos->server = -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Initialize client. */ | ||||
| static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	if (!_start_daemon(dmeventd_path, fifos)) | ||||
| 		return_0; | ||||
|  | ||||
| 	return init_fifos(fifos); | ||||
| } | ||||
|  | ||||
| void fini_fifos(struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	if (fifos->client >= 0 && close(fifos->client)) | ||||
| 		log_sys_debug("close", fifos->client_path); | ||||
|  | ||||
| 	if (fifos->server >= 0) { | ||||
| 		if (flock(fifos->server, LOCK_UN)) | ||||
| 			log_sys_debug("flock unlock", fifos->server_path); | ||||
|  | ||||
| 		if (close(fifos->server)) | ||||
| 			log_sys_debug("close", fifos->server_path); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Get uuid of a device */ | ||||
| static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	struct dm_task *dmt; | ||||
| 	struct dm_info info; | ||||
|  | ||||
| 	if (!(dmt = dm_task_create(DM_DEVICE_INFO))) { | ||||
| 		log_error("_get_device_info: dm_task creation for info failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (dmevh->uuid) { | ||||
| 		if (!dm_task_set_uuid(dmt, dmevh->uuid)) | ||||
| 			goto_bad; | ||||
| 	} else if (dmevh->dev_name) { | ||||
| 		if (!dm_task_set_name(dmt, dmevh->dev_name)) | ||||
| 			goto_bad; | ||||
| 	} else if (dmevh->major && dmevh->minor) { | ||||
| 		if (!dm_task_set_major(dmt, dmevh->major) || | ||||
| 		    !dm_task_set_minor(dmt, dmevh->minor)) | ||||
| 			goto_bad; | ||||
| 	} | ||||
|  | ||||
| 	/* FIXME Add name or uuid or devno to messages */ | ||||
| 	if (!dm_task_run(dmt)) { | ||||
| 		log_error("_get_device_info: dm_task_run() failed"); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_task_get_info(dmt, &info)) { | ||||
| 		log_error("_get_device_info: failed to get info for device"); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!info.exists) { | ||||
| 		log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found", | ||||
| 			  dmevh->uuid ? : "", | ||||
| 			  (!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "", | ||||
| 			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "", | ||||
| 			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? dmevh->major : 0, | ||||
| 			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ":" : "", | ||||
| 			  (!dmevh->uuid && !dmevh->dev_name && dmevh->minor > 0) ? dmevh->minor : 0, | ||||
| 			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) && dmevh->minor == 0 ? "0" : "", | ||||
| 			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ") " : ""); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	return dmt; | ||||
|  | ||||
|       bad: | ||||
| 	dm_task_destroy(dmt); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* Handle the event (de)registration call and return negative error codes. */ | ||||
| static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_message *msg, | ||||
| 		     const char *dso_name, const char *dev_name, | ||||
| 		     enum dm_event_mask evmask, uint32_t timeout) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct dm_event_fifos fifos = { | ||||
| 		.server = -1, | ||||
| 		.client = -1, | ||||
| 		/* FIXME Make these either configurable or depend directly on dmeventd_path */ | ||||
| 		.client_path = DM_EVENT_FIFO_CLIENT, | ||||
| 		.server_path = DM_EVENT_FIFO_SERVER | ||||
| 	}; | ||||
|  | ||||
| 	if (!_init_client(dmeventd_path, &fifos)) { | ||||
| 		stack; | ||||
| 		return -ESRCH; | ||||
| 	} | ||||
|  | ||||
| 	ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0); | ||||
|  | ||||
| 	dm_free(msg->data); | ||||
| 	msg->data = 0; | ||||
|  | ||||
| 	if (!ret) | ||||
| 		ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout); | ||||
|  | ||||
| 	/* what is the opposite of init? */ | ||||
| 	fini_fifos(&fifos); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* External library interface. */ | ||||
| int dm_event_register_handler(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	int ret = 1, err; | ||||
| 	const char *uuid; | ||||
| 	struct dm_task *dmt; | ||||
| 	struct dm_event_daemon_message msg = { 0 }; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) | ||||
| 		return_0; | ||||
|  | ||||
| 	uuid = dm_task_get_uuid(dmt); | ||||
|  | ||||
| 	if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") && | ||||
| 	    !strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") && | ||||
| 	    !strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") && | ||||
| 	    !strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so")) | ||||
| 		log_warn("WARNING: %s: dmeventd plugins are deprecated", dmevh->dso); | ||||
|  | ||||
|  | ||||
| 	if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg, | ||||
| 			     dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { | ||||
| 		log_error("%s: event registration failed: %s", | ||||
| 			  dm_task_get_name(dmt), | ||||
| 			  msg.data ? msg.data : strerror(-err)); | ||||
| 		ret = 0; | ||||
| 	} | ||||
|  | ||||
| 	dm_free(msg.data); | ||||
|  | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int dm_event_unregister_handler(const struct dm_event_handler *dmevh) | ||||
| { | ||||
| 	int ret = 1, err; | ||||
| 	const char *uuid; | ||||
| 	struct dm_task *dmt; | ||||
| 	struct dm_event_daemon_message msg = { 0 }; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) | ||||
| 		return_0; | ||||
|  | ||||
| 	uuid = dm_task_get_uuid(dmt); | ||||
|  | ||||
| 	if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg, | ||||
| 			    dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { | ||||
| 		log_error("%s: event deregistration failed: %s", | ||||
| 			  dm_task_get_name(dmt), | ||||
| 			  msg.data ? msg.data : strerror(-err)); | ||||
| 		ret = 0; | ||||
| 	} | ||||
|  | ||||
| 	dm_free(msg.data); | ||||
|  | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* Fetch a string off src and duplicate it into *dest. */ | ||||
| /* FIXME: move to separate module to share with the daemon. */ | ||||
| static char *_fetch_string(char **src, const int delimiter) | ||||
| { | ||||
| 	char *p, *ret; | ||||
|  | ||||
| 	if ((p = strchr(*src, delimiter))) | ||||
| 		*p = 0; | ||||
|  | ||||
| 	if ((ret = dm_strdup(*src))) | ||||
| 		*src += strlen(ret) + 1; | ||||
|  | ||||
| 	if (p) | ||||
| 		*p = delimiter; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* Parse a device message from the daemon. */ | ||||
| static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name, | ||||
| 			 char **uuid, enum dm_event_mask *evmask) | ||||
| { | ||||
| 	char *id; | ||||
| 	char *p = msg->data; | ||||
|  | ||||
| 	if ((id = _fetch_string(&p, ' ')) && | ||||
| 	    (*dso_name = _fetch_string(&p, ' ')) && | ||||
| 	    (*uuid = _fetch_string(&p, ' '))) { | ||||
| 		*evmask = atoi(p); | ||||
| 		dm_free(id); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	dm_free(id); | ||||
| 	return -ENOMEM; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns 0 if handler found; error (-ENOMEM, -ENOENT) otherwise. | ||||
|  */ | ||||
| int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	const char *uuid = NULL; | ||||
| 	char *reply_dso = NULL, *reply_uuid = NULL; | ||||
| 	enum dm_event_mask reply_mask = 0; | ||||
| 	struct dm_task *dmt = NULL; | ||||
| 	struct dm_event_daemon_message msg = { 0 }; | ||||
| 	struct dm_info info; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		log_debug("Device does not exists (uuid=%s, name=%s, %d:%d).", | ||||
| 			  dmevh->uuid, dmevh->dev_name, | ||||
| 			  dmevh->major, dmevh->minor); | ||||
| 		ret = -ENODEV; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	uuid = dm_task_get_uuid(dmt); | ||||
|  | ||||
| 	if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE : | ||||
| 		      DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path, | ||||
| 		      &msg, dmevh->dso, uuid, dmevh->mask, 0)) { | ||||
| 		log_debug("%s: device not registered.", dm_task_get_name(dmt)); | ||||
| 		ret = -ENOENT; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	/* FIXME this will probably horribly break if we get | ||||
| 	   ill-formatted reply */ | ||||
| 	ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask); | ||||
|  | ||||
| 	dm_task_destroy(dmt); | ||||
| 	dmt = NULL; | ||||
|  | ||||
| 	dm_free(msg.data); | ||||
| 	msg.data = NULL; | ||||
|  | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
| 	if (!reply_uuid) { | ||||
| 		ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */ | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dmevh->uuid = dm_strdup(reply_uuid))) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */ | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	dm_event_handler_set_dso(dmevh, reply_dso); | ||||
| 	dm_event_handler_set_event_mask(dmevh, reply_mask); | ||||
|  | ||||
| 	dm_free(reply_dso); | ||||
| 	reply_dso = NULL; | ||||
|  | ||||
| 	dm_free(reply_uuid); | ||||
| 	reply_uuid = NULL; | ||||
|  | ||||
| 	if (!(dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)))) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_task_get_info(dmt, &info)) { | ||||
| 		ret = -1; | ||||
| 		goto fail; | ||||
| 	} | ||||
|  | ||||
| 	dmevh->major = info.major; | ||||
| 	dmevh->minor = info.minor; | ||||
|  | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return ret; | ||||
|  | ||||
|  fail: | ||||
| 	dm_free(msg.data); | ||||
| 	dm_free(reply_dso); | ||||
| 	dm_free(reply_uuid); | ||||
| 	_dm_event_handler_clear_dev_info(dmevh); | ||||
| 	if (dmt) | ||||
| 		dm_task_destroy(dmt); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * You can (and have to) call this at the stage of the protocol where | ||||
|  *     daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0) | ||||
|  * | ||||
|  * would be normally sent. This call will parse the version reply from | ||||
|  * dmeventd, in addition to above call. It is not safe to call this at any | ||||
|  * other place in the protocol. | ||||
|  * | ||||
|  * This is an internal function, not exposed in the public API. | ||||
|  */ | ||||
|  | ||||
| int dm_event_get_version(struct dm_event_fifos *fifos, int *version) { | ||||
| 	char *p; | ||||
| 	struct dm_event_daemon_message msg = { 0 }; | ||||
|  | ||||
| 	if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0)) | ||||
| 		return 0; | ||||
| 	p = msg.data; | ||||
| 	*version = 0; | ||||
|  | ||||
| 	if (!p || !(p = strchr(p, ' '))) /* Message ID */ | ||||
| 		return 0; | ||||
| 	if (!(p = strchr(p + 1, ' '))) /* HELLO */ | ||||
| 		return 0; | ||||
| 	if ((p = strchr(p + 1, ' '))) /* HELLO, once more */ | ||||
| 		*version = atoi(p); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| #if 0				/* left out for now */ | ||||
|  | ||||
| static char *_skip_string(char *src, const int delimiter) | ||||
| { | ||||
| 	src = srtchr(src, delimiter); | ||||
| 	if (src && *(src + 1)) | ||||
| 		return src + 1; | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| int dm_event_set_timeout(const char *device_path, uint32_t timeout) | ||||
| { | ||||
| 	struct dm_event_daemon_message msg = { 0 }; | ||||
|  | ||||
| 	if (!device_exists(device_path)) | ||||
| 		return -ENODEV; | ||||
|  | ||||
| 	return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg, | ||||
| 			 NULL, device_path, 0, timeout); | ||||
| } | ||||
|  | ||||
| int dm_event_get_timeout(const char *device_path, uint32_t *timeout) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct dm_event_daemon_message msg = { 0 }; | ||||
|  | ||||
| 	if (!device_exists(device_path)) | ||||
| 		return -ENODEV; | ||||
|  | ||||
| 	if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path, | ||||
| 			     0, 0))) { | ||||
| 		char *p = _skip_string(msg.data, ' '); | ||||
| 		if (!p) { | ||||
| 			log_error("malformed reply from dmeventd '%s'\n", | ||||
| 				  msg.data); | ||||
| 			dm_free(msg.data); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 		*timeout = atoi(p); | ||||
| 	} | ||||
| 	dm_free(msg.data); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
| @@ -1,116 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Note that this file is released only as part of a technology preview | ||||
|  * and its contents may change in future updates in ways that do not | ||||
|  * preserve compatibility. | ||||
|  */ | ||||
|  | ||||
| #ifndef LIB_DMEVENT_H | ||||
| #define LIB_DMEVENT_H | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| /* | ||||
|  * Event library interface. | ||||
|  */ | ||||
|  | ||||
| enum dm_event_mask { | ||||
| 	DM_EVENT_SETTINGS_MASK  = 0x0000FF, | ||||
| 	DM_EVENT_SINGLE		= 0x000001, /* Report multiple errors just once. */ | ||||
| 	DM_EVENT_MULTI		= 0x000002, /* Report all of them. */ | ||||
|  | ||||
| 	DM_EVENT_ERROR_MASK     = 0x00FF00, | ||||
| 	DM_EVENT_SECTOR_ERROR	= 0x000100, /* Failure on a particular sector. */ | ||||
| 	DM_EVENT_DEVICE_ERROR	= 0x000200, /* Device failure. */ | ||||
| 	DM_EVENT_PATH_ERROR	= 0x000400, /* Failure on an io path. */ | ||||
| 	DM_EVENT_ADAPTOR_ERROR	= 0x000800, /* Failure of a host adaptor. */ | ||||
|  | ||||
| 	DM_EVENT_STATUS_MASK    = 0xFF0000, | ||||
| 	DM_EVENT_SYNC_STATUS	= 0x010000, /* Mirror synchronization completed/failed. */ | ||||
| 	DM_EVENT_TIMEOUT	= 0x020000, /* Timeout has occured */ | ||||
|  | ||||
| 	DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */ | ||||
| }; | ||||
|  | ||||
| #define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK | ||||
| #define DM_EVENT_PROTOCOL_VERSION 2 | ||||
|  | ||||
| struct dm_task; | ||||
| struct dm_event_handler; | ||||
|  | ||||
| struct dm_event_handler *dm_event_handler_create(void); | ||||
| void dm_event_handler_destroy(struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* | ||||
|  * Path of shared library to handle events. | ||||
|  * | ||||
|  * All of dmeventd, dso, device_name and uuid strings are duplicated so | ||||
|  * you do not need to keep the pointers valid after the call succeeds. | ||||
|  * They may return -ENOMEM though. | ||||
|  */ | ||||
| int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path); | ||||
|  | ||||
| /* | ||||
|  * Path of dmeventd binary. | ||||
|  */ | ||||
| int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path); | ||||
|  | ||||
| /* | ||||
|  * Identify the device to monitor by exactly one of device_name, uuid or | ||||
|  * device number. String arguments are duplicated, see above. | ||||
|  */ | ||||
| int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name); | ||||
|  | ||||
| int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid); | ||||
|  | ||||
| void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major); | ||||
| void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor); | ||||
| void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout); | ||||
|  | ||||
| /* | ||||
|  * Specify mask for events to monitor. | ||||
|  */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh, | ||||
| 				     enum dm_event_mask evmask); | ||||
|  | ||||
| const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh); | ||||
| const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh); | ||||
| const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_major(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_minor(const struct dm_event_handler *dmevh); | ||||
| int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh); | ||||
| // FIXME  misuse of bitmask as enum | ||||
| enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* FIXME Review interface (what about this next thing?) */ | ||||
| int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next); | ||||
|  | ||||
| /* | ||||
|  * Initiate monitoring using dmeventd. | ||||
|  */ | ||||
| int dm_event_register_handler(const struct dm_event_handler *dmevh); | ||||
| int dm_event_unregister_handler(const struct dm_event_handler *dmevh); | ||||
|  | ||||
| /* Prototypes for DSO interface, see dmeventd.c, struct dso_data for | ||||
|    detailed descriptions. */ | ||||
| // FIXME  misuse of bitmask as enum | ||||
| void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user); | ||||
| int register_device(const char *device_name, const char *uuid, int major, int minor, void **user); | ||||
| int unregister_device(const char *device_name, const char *uuid, int major, | ||||
| 		      int minor, void **user); | ||||
|  | ||||
| #endif | ||||
| @@ -1,11 +0,0 @@ | ||||
| prefix=@prefix@ | ||||
| exec_prefix=@exec_prefix@ | ||||
| libdir=@libdir@ | ||||
| includedir=@includedir@ | ||||
|  | ||||
| Name: devmapper-event | ||||
| Description: device-mapper event library | ||||
| Version: @DM_LIB_PATCHLEVEL@ | ||||
| Cflags: -I${includedir} | ||||
| Libs: -L${libdir} -ldevmapper-event | ||||
| Requires.private: devmapper | ||||
| @@ -1,46 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005, 2011 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| SUBDIRS += lvm2 | ||||
|  | ||||
| ifneq ("@MIRRORS@", "none") | ||||
|   SUBDIRS += mirror | ||||
| endif | ||||
|  | ||||
| ifneq ("@SNAPSHOTS@", "none") | ||||
|   SUBDIRS += snapshot | ||||
| endif | ||||
|  | ||||
| ifneq ("@RAID@", "none") | ||||
|   SUBDIRS += raid | ||||
| endif | ||||
|  | ||||
| ifneq ("@THIN@", "none") | ||||
|   SUBDIRS += thin | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = lvm2 mirror snapshot raid thin | ||||
| endif | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| snapshot: lvm2 | ||||
| mirror: lvm2 | ||||
| raid: lvm2 | ||||
| thin: lvm2 | ||||
| @@ -1,7 +0,0 @@ | ||||
| dmeventd_lvm2_init | ||||
| dmeventd_lvm2_exit | ||||
| dmeventd_lvm2_lock | ||||
| dmeventd_lvm2_unlock | ||||
| dmeventd_lvm2_pool | ||||
| dmeventd_lvm2_run | ||||
| dmeventd_lvm2_command | ||||
| @@ -1,31 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2010-2014 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| CLDFLAGS += -L$(top_builddir)/tools | ||||
|  | ||||
| SOURCES = dmeventd_lvm.c | ||||
|  | ||||
| LIB_SHARED = libdevmapper-event-lvm2.$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS) | ||||
|  | ||||
| install_lvm2: install_lib_shared | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,176 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
| #include "log.h" | ||||
|  | ||||
| #include "lvm2cmd.h" | ||||
| #include "dmeventd_lvm.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
| #include <syslog.h> | ||||
|  | ||||
| extern int dmeventd_debug; | ||||
|  | ||||
| /* | ||||
|  * register_device() is called first and performs initialisation. | ||||
|  * Only one device may be registered or unregistered at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| /* | ||||
|  * Number of active registrations. | ||||
|  */ | ||||
| static int _register_count = 0; | ||||
| static struct dm_pool *_mem_pool = NULL; | ||||
| static void *_lvm_handle = NULL; | ||||
|  | ||||
| /* | ||||
|  * Currently only one event can be processed at a time. | ||||
|  */ | ||||
| static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| /* | ||||
|  * FIXME Do not pass things directly to syslog, rather use the existing logging | ||||
|  * facilities to sort logging ... however that mechanism needs to be somehow | ||||
|  * configurable and we don't have that option yet | ||||
|  */ | ||||
| static void _temporary_log_fn(int level, | ||||
| 			      const char *file __attribute__((unused)), | ||||
| 			      int line __attribute__((unused)), | ||||
| 			      int dm_errno __attribute__((unused)), | ||||
| 			      const char *message) | ||||
| { | ||||
| 	level &= ~(_LOG_STDERR | _LOG_ONCE); | ||||
|  | ||||
| 	switch (level) { | ||||
| 	case _LOG_DEBUG: | ||||
| 		if (dmeventd_debug >= 3) | ||||
| 			syslog(LOG_DEBUG, "%s", message); | ||||
| 		break; | ||||
| 	case _LOG_INFO: | ||||
| 		if (dmeventd_debug >= 2) | ||||
| 			syslog(LOG_INFO, "%s", message); | ||||
| 		break; | ||||
| 	case _LOG_NOTICE: | ||||
| 		if (dmeventd_debug >= 1) | ||||
| 			syslog(LOG_NOTICE, "%s", message); | ||||
| 		break; | ||||
| 	case _LOG_WARN: | ||||
| 		syslog(LOG_WARNING, "%s", message); | ||||
| 		break; | ||||
| 	case _LOG_ERR: | ||||
| 		syslog(LOG_ERR, "%s", message); | ||||
| 		break; | ||||
| 	default: | ||||
| 		syslog(LOG_CRIT, "%s", message); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void dmeventd_lvm2_lock(void) | ||||
| { | ||||
| 	pthread_mutex_lock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| void dmeventd_lvm2_unlock(void) | ||||
| { | ||||
| 	pthread_mutex_unlock(&_event_mutex); | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_init(void) | ||||
| { | ||||
| 	int r = 0; | ||||
|  | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	/* | ||||
| 	 * Need some space for allocations.  1024 should be more | ||||
| 	 * than enough for what we need (device mapper name splitting) | ||||
| 	 */ | ||||
| 	if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!_lvm_handle) { | ||||
| 		lvm2_log_fn(_temporary_log_fn); | ||||
| 		if (!(_lvm_handle = lvm2_init())) { | ||||
| 			dm_pool_destroy(_mem_pool); | ||||
| 			_mem_pool = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		lvm2_disable_dmeventd_monitoring(_lvm_handle); | ||||
| 		/* FIXME Temporary: move to dmeventd core */ | ||||
| 		lvm2_run(_lvm_handle, "_memlock_inc"); | ||||
| 	} | ||||
|  | ||||
| 	_register_count++; | ||||
| 	r = 1; | ||||
|  | ||||
| out: | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| void dmeventd_lvm2_exit(void) | ||||
| { | ||||
| 	pthread_mutex_lock(&_register_mutex); | ||||
|  | ||||
| 	if (!--_register_count) { | ||||
| 		lvm2_run(_lvm_handle, "_memlock_dec"); | ||||
| 		dm_pool_destroy(_mem_pool); | ||||
| 		_mem_pool = NULL; | ||||
| 		lvm2_exit(_lvm_handle); | ||||
| 		_lvm_handle = NULL; | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_unlock(&_register_mutex); | ||||
| } | ||||
|  | ||||
| struct dm_pool *dmeventd_lvm2_pool(void) | ||||
| { | ||||
| 	return _mem_pool; | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_run(const char *cmdline) | ||||
| { | ||||
| 	return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED); | ||||
| } | ||||
|  | ||||
| int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, | ||||
| 			  const char *cmd, const char *device) | ||||
| { | ||||
| 	char *vg = NULL, *lv = NULL, *layer; | ||||
| 	int r; | ||||
|  | ||||
| 	if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) { | ||||
| 		syslog(LOG_ERR, "Unable to determine VG name from %s.\n", | ||||
| 		       device); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* strip off the mirror component designations */ | ||||
| 	if ((layer = strstr(lv, "_mimagetmp")) || | ||||
| 	    (layer = strstr(lv, "_mlog"))) | ||||
| 		*layer = '\0'; | ||||
|  | ||||
| 	r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv); | ||||
|  | ||||
| 	dm_pool_free(mem, vg); | ||||
|  | ||||
| 	if (r < 0) { | ||||
| 		syslog(LOG_ERR, "Unable to form LVM command. (too long).\n"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,42 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Wrappers around liblvm2cmd functions for dmeventd plug-ins. | ||||
|  * | ||||
|  * liblvm2cmd is not thread-safe so the locking in this library helps dmeventd | ||||
|  * threads to co-operate in sharing a single instance. | ||||
|  * | ||||
|  * FIXME Either support this properly as a generic liblvm2cmd wrapper or make | ||||
|  * liblvm2cmd thread-safe so this can go away. | ||||
|  */ | ||||
|  | ||||
| #ifndef _DMEVENTD_LVMWRAP_H | ||||
| #define _DMEVENTD_LVMWRAP_H | ||||
|  | ||||
| struct dm_pool; | ||||
|  | ||||
| int dmeventd_lvm2_init(void); | ||||
| void dmeventd_lvm2_exit(void); | ||||
| int dmeventd_lvm2_run(const char *cmdline); | ||||
|  | ||||
| void dmeventd_lvm2_lock(void); | ||||
| void dmeventd_lvm2_unlock(void); | ||||
|  | ||||
| struct dm_pool *dmeventd_lvm2_pool(void); | ||||
|  | ||||
| int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size, | ||||
| 			  const char *cmd, const char *device); | ||||
|  | ||||
| #endif /* _DMEVENTD_LVMWRAP_H */ | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,37 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005, 2008-2014 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_mirror.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2mirror | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| CFLOW_LIST = $(SOURCES) | ||||
| CFLOW_LIST_TARGET = $(LIB_NAME).cflow | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LIBS += -ldevmapper-event-lvm2 -ldevmapper | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,233 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
|  | ||||
| #include "libdevmapper-event.h" | ||||
| #include "dmeventd_lvm.h" | ||||
| #include "defaults.h" | ||||
|  | ||||
| #include <syslog.h> /* FIXME Replace syslog with multilog */ | ||||
| /* FIXME Missing openlog? */ | ||||
| /* FIXME Replace most syslogs with log_error() style messages and add complete context. */ | ||||
| /* FIXME Reformat to 80 char lines. */ | ||||
|  | ||||
| #define ME_IGNORE    0 | ||||
| #define ME_INSYNC    1 | ||||
| #define ME_FAILURE   2 | ||||
|  | ||||
| static int _process_status_code(const char status_code, const char *dev_name, | ||||
| 				const char *dev_type, int r) | ||||
| { | ||||
| 	/* | ||||
| 	 *    A => Alive - No failures | ||||
| 	 *    D => Dead - A write failure occurred leaving mirror out-of-sync | ||||
| 	 *    F => Flush failed. | ||||
| 	 *    S => Sync - A sychronization failure occurred, mirror out-of-sync | ||||
| 	 *    R => Read - A read failure occurred, mirror data unaffected | ||||
| 	 *    U => Unclassified failure (bug) | ||||
| 	 */  | ||||
| 	if (status_code == 'F') { | ||||
| 		syslog(LOG_ERR, "%s device %s flush failed.", | ||||
| 		       dev_type, dev_name); | ||||
| 		r = ME_FAILURE; | ||||
| 	} else if (status_code == 'S') | ||||
| 		syslog(LOG_ERR, "%s device %s sync failed.", | ||||
| 		       dev_type, dev_name); | ||||
| 	else if (status_code == 'R') | ||||
| 		syslog(LOG_ERR, "%s device %s read failed.", | ||||
| 		       dev_type, dev_name); | ||||
| 	else if (status_code != 'A') { | ||||
| 		syslog(LOG_ERR, "%s device %s has failed (%c).", | ||||
| 		       dev_type, dev_name, status_code); | ||||
| 		r = ME_FAILURE; | ||||
| 	} | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _get_mirror_event(char *params) | ||||
| { | ||||
| 	int i, r = ME_INSYNC; | ||||
| 	char **args = NULL; | ||||
| 	char *dev_status_str; | ||||
| 	char *log_status_str; | ||||
| 	char *sync_str; | ||||
| 	char *p = NULL; | ||||
| 	int log_argc, num_devs; | ||||
|  | ||||
| 	/* | ||||
| 	 * dm core parms:	     0 409600 mirror | ||||
| 	 * Mirror core parms:	     2 253:4 253:5 400/400 | ||||
| 	 * New-style failure params: 1 AA | ||||
| 	 * New-style log params:     3 cluster 253:3 A | ||||
| 	 *			 or  3 disk 253:3 A | ||||
| 	 *			 or  1 core | ||||
| 	 */ | ||||
|  | ||||
| 	/* number of devices */ | ||||
| 	if (!dm_split_words(params, 1, 0, &p)) | ||||
| 		goto out_parse; | ||||
|  | ||||
| 	if (!(num_devs = atoi(p)) || | ||||
| 	    (num_devs > DEFAULT_MIRROR_MAX_IMAGES) || (num_devs < 0)) | ||||
| 		goto out_parse; | ||||
| 	p += strlen(p) + 1; | ||||
|  | ||||
| 	/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */ | ||||
| 	args = dm_malloc((num_devs + 7) * sizeof(char *)); | ||||
| 	if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5) | ||||
| 		goto out_parse; | ||||
|  | ||||
| 	/* FIXME: Code differs from lib/mirror/mirrored.c */ | ||||
| 	dev_status_str = args[2 + num_devs]; | ||||
| 	log_argc = atoi(args[3 + num_devs]); | ||||
| 	log_status_str = args[3 + num_devs + log_argc]; | ||||
| 	sync_str = args[num_devs]; | ||||
|  | ||||
| 	/* Check for bad mirror devices */ | ||||
| 	for (i = 0; i < num_devs; i++) | ||||
| 		r = _process_status_code(dev_status_str[i], args[i], | ||||
| 			i ? "Secondary mirror" : "Primary mirror", r); | ||||
|  | ||||
| 	/* Check for bad disk log device */ | ||||
| 	if (log_argc > 1) | ||||
| 		r = _process_status_code(log_status_str[0], | ||||
| 					 args[2 + num_devs + log_argc], | ||||
| 					 "Log", r); | ||||
|  | ||||
| 	if (r == ME_FAILURE) | ||||
| 		goto out; | ||||
|  | ||||
| 	p = strstr(sync_str, "/"); | ||||
| 	if (p) { | ||||
| 		p[0] = '\0'; | ||||
| 		if (strcmp(sync_str, p+1)) | ||||
| 			r = ME_IGNORE; | ||||
| 		p[0] = '/'; | ||||
| 	} else | ||||
| 		goto out_parse; | ||||
|  | ||||
| out: | ||||
| 	dm_free(args); | ||||
| 	return r; | ||||
|  | ||||
| out_parse: | ||||
| 	dm_free(args); | ||||
| 	syslog(LOG_ERR, "Unable to parse mirror status string."); | ||||
| 	return ME_IGNORE; | ||||
| } | ||||
|  | ||||
| static int _remove_failed_devices(const char *device) | ||||
| { | ||||
| 	int r; | ||||
| #define CMD_SIZE 256	/* FIXME Use system restriction */ | ||||
| 	char cmd_str[CMD_SIZE]; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str), | ||||
| 				  "lvconvert --config devices{ignore_suspended_devices=1} " | ||||
| 				  "--repair --use-policies", device)) | ||||
| 		return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */ | ||||
|  | ||||
| 	r = dmeventd_lvm2_run(cmd_str); | ||||
|  | ||||
| 	syslog(LOG_INFO, "Repair of mirrored device %s %s.", device, | ||||
| 	       (r) ? "finished successfully" : "failed"); | ||||
|  | ||||
| 	return (r) ? 0 : -1; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **unused __attribute__((unused))) | ||||
| { | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
|  | ||||
| 	dmeventd_lvm2_lock(); | ||||
|  | ||||
| 	do { | ||||
| 		next = dm_get_next_target(dmt, next, &start, &length, | ||||
| 					  &target_type, ¶ms); | ||||
|  | ||||
| 		if (!target_type) { | ||||
| 			syslog(LOG_INFO, "%s mapping lost.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (strcmp(target_type, "mirror")) { | ||||
| 			syslog(LOG_INFO, "%s has unmirrored portion.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		switch(_get_mirror_event(params)) { | ||||
| 		case ME_INSYNC: | ||||
| 			/* FIXME: all we really know is that this | ||||
| 			   _part_ of the device is in sync | ||||
| 			   Also, this is not an error | ||||
| 			*/ | ||||
| 			syslog(LOG_NOTICE, "%s is now in-sync.", device); | ||||
| 			break; | ||||
| 		case ME_FAILURE: | ||||
| 			syslog(LOG_ERR, "Device failure in %s.", device); | ||||
| 			if (_remove_failed_devices(device)) | ||||
| 				/* FIXME Why are all the error return codes unused? Get rid of them? */ | ||||
| 				syslog(LOG_ERR, "Failed to remove faulty devices in %s.", | ||||
| 				       device); | ||||
| 			/* Should check before warning user that device is now linear | ||||
| 			else | ||||
| 				syslog(LOG_NOTICE, "%s is now a linear device.\n", | ||||
| 					device); | ||||
| 			*/ | ||||
| 			break; | ||||
| 		case ME_IGNORE: | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* FIXME Provide value then! */ | ||||
| 			syslog(LOG_INFO, "Unknown event received."); | ||||
| 		} | ||||
| 	} while (next); | ||||
|  | ||||
| 	dmeventd_lvm2_unlock(); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **unused __attribute__((unused))) | ||||
| { | ||||
| 	if (!dmeventd_lvm2_init()) | ||||
| 		return 0; | ||||
|  | ||||
| 	syslog(LOG_INFO, "Monitoring mirror device %s for events.", device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **unused __attribute__((unused))) | ||||
| { | ||||
| 	syslog(LOG_INFO, "No longer monitoring mirror device %s for events.", | ||||
| 	       device); | ||||
| 	dmeventd_lvm2_exit(); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,36 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2011-2014 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_raid.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2raid | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| CFLOW_LIST = $(SOURCES) | ||||
| CFLOW_LIST_TARGET = $(LIB_NAME).cflow | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LIBS += -ldevmapper-event-lvm2 -ldevmapper | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,180 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
|  | ||||
| #include "libdevmapper-event.h" | ||||
| #include "dmeventd_lvm.h" | ||||
|  | ||||
| #include <syslog.h> /* FIXME Replace syslog with multilog */ | ||||
| /* FIXME Missing openlog? */ | ||||
| /* FIXME Replace most syslogs with log_error() style messages and add complete context. */ | ||||
| /* FIXME Reformat to 80 char lines. */ | ||||
|  | ||||
| /* | ||||
|  * run_repair is a close copy to | ||||
|  * plugins/mirror/dmeventd_mirror.c:_remove_failed_devices() | ||||
|  */ | ||||
| static int run_repair(const char *device) | ||||
| { | ||||
| 	int r; | ||||
| #define CMD_SIZE 256	/* FIXME Use system restriction */ | ||||
| 	char cmd_str[CMD_SIZE]; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str), | ||||
| 				  "lvscan --cache", device)) | ||||
| 		return -1; | ||||
|  | ||||
| 	r = dmeventd_lvm2_run(cmd_str); | ||||
|  | ||||
| 	if (!r) | ||||
| 		syslog(LOG_INFO, "Re-scan of RAID device %s failed.", device); | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str), | ||||
| 				  "lvconvert --config devices{ignore_suspended_devices=1} " | ||||
| 				  "--repair --use-policies", device)) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* if repair goes OK, report success even if lvscan has failed */ | ||||
| 	r = dmeventd_lvm2_run(cmd_str); | ||||
|  | ||||
| 	if (!r) | ||||
| 		syslog(LOG_INFO, "Repair of RAID device %s failed.", device); | ||||
|  | ||||
| 	return (r) ? 0 : -1; | ||||
| } | ||||
|  | ||||
| static int _process_raid_event(char *params, const char *device) | ||||
| { | ||||
| 	int i, n, failure = 0; | ||||
| 	char *p, *a[4]; | ||||
| 	char *raid_type; | ||||
| 	char *num_devices; | ||||
| 	char *health_chars; | ||||
| 	char *resync_ratio; | ||||
|  | ||||
| 	/* | ||||
| 	 * RAID parms:     <raid_type> <#raid_disks> \ | ||||
| 	 *                 <health chars> <resync ratio> | ||||
| 	 */ | ||||
| 	if (!dm_split_words(params, 4, 0, a)) { | ||||
| 		syslog(LOG_ERR, "Failed to process status line for %s\n", | ||||
| 		       device); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	raid_type = a[0]; | ||||
| 	num_devices = a[1]; | ||||
| 	health_chars = a[2]; | ||||
| 	resync_ratio = a[3]; | ||||
|  | ||||
| 	if (!(n = atoi(num_devices))) { | ||||
| 		syslog(LOG_ERR, "Failed to parse number of devices for %s: %s", | ||||
| 		       device, num_devices); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < n; i++) { | ||||
| 		switch (health_chars[i]) { | ||||
| 		case 'A': | ||||
| 			/* Device is 'A'live and well */ | ||||
| 		case 'a': | ||||
| 			/* Device is 'a'live, but not yet in-sync */ | ||||
| 			break; | ||||
| 		case 'D': | ||||
| 			syslog(LOG_ERR, | ||||
| 			       "Device #%d of %s array, %s, has failed.", | ||||
| 			       i, raid_type, device); | ||||
| 			failure++; | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* Unhandled character returned from kernel */ | ||||
| 			break; | ||||
| 		} | ||||
| 		if (failure) | ||||
| 			return run_repair(device); | ||||
| 	} | ||||
|  | ||||
| 	p = strstr(resync_ratio, "/"); | ||||
| 	if (!p) { | ||||
| 		syslog(LOG_ERR, "Failed to parse resync_ratio for %s: %s", | ||||
| 		       device, resync_ratio); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	p[0] = '\0'; | ||||
| 	syslog(LOG_INFO, "%s array, %s, is %s in-sync.", | ||||
| 	       raid_type, device, strcmp(resync_ratio, p+1) ? "not" : "now"); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **unused __attribute__((unused))) | ||||
| { | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
|  | ||||
| 	dmeventd_lvm2_lock(); | ||||
|  | ||||
| 	do { | ||||
| 		next = dm_get_next_target(dmt, next, &start, &length, | ||||
| 					  &target_type, ¶ms); | ||||
|  | ||||
| 		if (!target_type) { | ||||
| 			syslog(LOG_INFO, "%s mapping lost.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (strcmp(target_type, "raid")) { | ||||
| 			syslog(LOG_INFO, "%s has non-raid portion.", device); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (_process_raid_event(params, device)) | ||||
| 			syslog(LOG_ERR, "Failed to process event for %s", | ||||
| 			       device); | ||||
| 	} while (next); | ||||
|  | ||||
| 	dmeventd_lvm2_unlock(); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **unused __attribute__((unused))) | ||||
| { | ||||
| 	if (!dmeventd_lvm2_init()) | ||||
| 		return 0; | ||||
|  | ||||
| 	syslog(LOG_INFO, "Monitoring RAID device %s for events.", device); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **unused __attribute__((unused))) | ||||
| { | ||||
| 	syslog(LOG_INFO, "No longer monitoring RAID device %s for events.", | ||||
| 	       device); | ||||
| 	dmeventd_lvm2_exit(); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,33 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of the LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_snapshot.c | ||||
|  | ||||
| LIB_SHARED = libdevmapper-event-lvm2snapshot.$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LIBS += -ldevmapper-event-lvm2 -ldevmapper | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,247 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
|  | ||||
| #include "libdevmapper-event.h" | ||||
| #include "dmeventd_lvm.h" | ||||
|  | ||||
| #include <sys/wait.h> | ||||
| #include <syslog.h> /* FIXME Replace syslog with multilog */ | ||||
| #include <stdarg.h> | ||||
| /* FIXME Missing openlog? */ | ||||
|  | ||||
| /* First warning when snapshot is 80% full. */ | ||||
| #define WARNING_THRESH 80 | ||||
| /* Run a check every 5%. */ | ||||
| #define CHECK_STEP 5 | ||||
| /* Do not bother checking snapshots less than 50% full. */ | ||||
| #define CHECK_MINIMUM 50 | ||||
|  | ||||
| #define UMOUNT_COMMAND "/bin/umount" | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	int percent_check; | ||||
| 	uint64_t known_size; | ||||
| 	char cmd_str[1024]; | ||||
| }; | ||||
|  | ||||
| static int _run(const char *cmd, ...) | ||||
| { | ||||
|         va_list ap; | ||||
|         int argc = 1; /* for argv[0], i.e. cmd */ | ||||
|         int i = 0; | ||||
|         const char **argv; | ||||
|         pid_t pid = fork(); | ||||
|         int status; | ||||
|  | ||||
|         if (pid == 0) { /* child */ | ||||
|                 va_start(ap, cmd); | ||||
|                 while (va_arg(ap, const char *)) | ||||
|                         ++ argc; | ||||
|                 va_end(ap); | ||||
|  | ||||
|                 /* + 1 for the terminating NULL */ | ||||
|                 argv = alloca(sizeof(const char *) * (argc + 1)); | ||||
|  | ||||
|                 argv[0] = cmd; | ||||
|                 va_start(ap, cmd); | ||||
|                 while ((argv[++i] = va_arg(ap, const char *))); | ||||
|                 va_end(ap); | ||||
|  | ||||
|                 execvp(cmd, (char **)argv); | ||||
|                 syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno)); | ||||
|                 exit(127); | ||||
|         } | ||||
|  | ||||
|         if (pid > 0) { /* parent */ | ||||
|                 if (waitpid(pid, &status, 0) != pid) | ||||
|                         return 0; /* waitpid failed */ | ||||
|                 if (!WIFEXITED(status) || WEXITSTATUS(status)) | ||||
|                         return 0; /* the child failed */ | ||||
|         } | ||||
|  | ||||
|         if (pid < 0) | ||||
|                 return 0; /* fork failed */ | ||||
|  | ||||
|         return 1; /* all good */ | ||||
| } | ||||
|  | ||||
| static int _extend(const char *cmd) | ||||
| { | ||||
| 	return dmeventd_lvm2_run(cmd); | ||||
| } | ||||
|  | ||||
| static void _umount(const char *device, int major, int minor) | ||||
| { | ||||
| 	FILE *mounts; | ||||
| 	char buffer[4096]; | ||||
| 	char *words[3]; | ||||
| 	struct stat st; | ||||
|  | ||||
| 	if (!(mounts = fopen("/proc/mounts", "r"))) { | ||||
| 		syslog(LOG_ERR, "Could not read /proc/mounts. Not umounting %s.\n", device); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	while (!feof(mounts)) { | ||||
| 		/* read a line of /proc/mounts */ | ||||
| 		if (!fgets(buffer, sizeof(buffer), mounts)) | ||||
| 			break; /* eof, likely */ | ||||
|  | ||||
| 		/* words[0] is the mount point and words[1] is the device path */ | ||||
| 		if (dm_split_words(buffer, 3, 0, words) < 2) | ||||
| 			continue; | ||||
|  | ||||
| 		/* find the major/minor of the device */ | ||||
| 		if (stat(words[0], &st)) | ||||
| 			continue; /* can't stat, skip this one */ | ||||
|  | ||||
| 		if (S_ISBLK(st.st_mode) && | ||||
| 		    major(st.st_rdev) == major && | ||||
| 		    minor(st.st_rdev) == minor) { | ||||
| 			syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]); | ||||
|                         if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL)) | ||||
|                                 syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n", | ||||
|                                        device, words[1], strerror(errno)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (fclose(mounts)) | ||||
| 		syslog(LOG_ERR, "Failed to close /proc/mounts.\n"); | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **private) | ||||
| { | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
| 	struct dm_status_snapshot *status = NULL; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
| 	int percent; | ||||
| 	struct dso_state *state = *private; | ||||
|  | ||||
| 	/* No longer monitoring, waiting for remove */ | ||||
| 	if (!state->percent_check) | ||||
| 		return; | ||||
|  | ||||
| 	dmeventd_lvm2_lock(); | ||||
|  | ||||
| 	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); | ||||
| 	if (!target_type) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!dm_get_status_snapshot(state->mem, params, &status)) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (status->invalid) { | ||||
| 		struct dm_info info; | ||||
| 		if (dm_task_get_info(dmt, &info)) { | ||||
| 			dmeventd_lvm2_unlock(); | ||||
| 			_umount(device, info.major, info.minor); | ||||
| 			return; | ||||
| 		} /* else; too bad, but this is best-effort thing... */ | ||||
| 	} | ||||
|  | ||||
| 	/* Snapshot size had changed. Clear the threshold. */ | ||||
| 	if (state->known_size != status->total_sectors) { | ||||
| 		state->percent_check = CHECK_MINIMUM; | ||||
| 		state->known_size = status->total_sectors; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If the snapshot has been invalidated or we failed to parse | ||||
| 	 * the status string. Report the full status string to syslog. | ||||
| 	 */ | ||||
| 	if (status->invalid || !status->total_sectors) { | ||||
| 		syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params); | ||||
| 		state->percent_check = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	percent = (int) (100 * status->used_sectors / status->total_sectors); | ||||
| 	if (percent >= state->percent_check) { | ||||
| 		/* Usage has raised more than CHECK_STEP since the last | ||||
| 		   time. Run actions. */ | ||||
| 		state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP; | ||||
|  | ||||
| 		if (percent >= WARNING_THRESH) /* Print a warning to syslog. */ | ||||
| 			syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent); | ||||
| 		/* Try to extend the snapshot, in accord with user-set policies */ | ||||
| 		if (!_extend(state->cmd_str)) | ||||
| 			syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device); | ||||
| 	} | ||||
|  | ||||
| out: | ||||
| 	if (status) | ||||
| 		dm_pool_free(state->mem, status); | ||||
| 	dmeventd_lvm2_unlock(); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **private) | ||||
| { | ||||
| 	struct dm_pool *statemem = NULL; | ||||
| 	struct dso_state *state; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init()) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!(statemem = dm_pool_create("snapshot_state", 512)) || | ||||
| 	    !(state = dm_pool_zalloc(statemem, sizeof(*state)))) | ||||
| 		goto bad; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_command(statemem, state->cmd_str, | ||||
| 				   sizeof(state->cmd_str), | ||||
| 				   "lvextend --use-policies", device)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	state->mem = statemem; | ||||
| 	state->percent_check = CHECK_MINIMUM; | ||||
| 	*private = state; | ||||
|  | ||||
| 	syslog(LOG_INFO, "Monitoring snapshot %s\n", device); | ||||
|  | ||||
| 	return 1; | ||||
| bad: | ||||
| 	if (statemem) | ||||
| 		dm_pool_destroy(statemem); | ||||
| 	dmeventd_lvm2_exit(); | ||||
| out: | ||||
| 	syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **private) | ||||
| { | ||||
| 	struct dso_state *state = *private; | ||||
|  | ||||
| 	syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device); | ||||
| 	dm_pool_destroy(state->mem); | ||||
| 	dmeventd_lvm2_exit(); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
| @@ -1,36 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2011-2014 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 | ||||
| CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2 | ||||
|  | ||||
| SOURCES = dmeventd_thin.c | ||||
|  | ||||
| LIB_NAME = libdevmapper-event-lvm2thin | ||||
| LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX) | ||||
| LIB_VERSION = $(LIB_VERSION_LVM) | ||||
|  | ||||
| CFLOW_LIST = $(SOURCES) | ||||
| CFLOW_LIST_TARGET = $(LIB_NAME).cflow | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| LIBS += -ldevmapper-event-lvm2 -ldevmapper | ||||
|  | ||||
| install_lvm2: install_dm_plugin | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,401 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #include "lib.h" | ||||
|  | ||||
| #include "libdevmapper-event.h" | ||||
| #include "dmeventd_lvm.h" | ||||
|  | ||||
| #include <sys/wait.h> | ||||
| #include <syslog.h> /* FIXME Replace syslog with multilog */ | ||||
| #include <stdarg.h> | ||||
| /* FIXME Missing openlog? */ | ||||
|  | ||||
| /* First warning when thin is 80% full. */ | ||||
| #define WARNING_THRESH 80 | ||||
| /* Run a check every 5%. */ | ||||
| #define CHECK_STEP 5 | ||||
| /* Do not bother checking thins less than 50% full. */ | ||||
| #define CHECK_MINIMUM 50 | ||||
|  | ||||
| #define UMOUNT_COMMAND "/bin/umount" | ||||
|  | ||||
| #define THIN_DEBUG 0 | ||||
|  | ||||
| struct dso_state { | ||||
| 	struct dm_pool *mem; | ||||
| 	int metadata_percent_check; | ||||
| 	int data_percent_check; | ||||
| 	uint64_t known_metadata_size; | ||||
| 	uint64_t known_data_size; | ||||
| 	char cmd_str[1024]; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* TODO - move this mountinfo code into library to be reusable */ | ||||
| #ifdef __linux__ | ||||
| #  include "kdev_t.h" | ||||
| #else | ||||
| #  define MAJOR(x) major((x)) | ||||
| #  define MINOR(x) minor((x)) | ||||
| #  define MKDEV(x,y) makedev((x),(y)) | ||||
| #endif | ||||
|  | ||||
| /* Get dependencies for device, and try to find matching device */ | ||||
| static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor) | ||||
| { | ||||
| 	struct dm_task *dmt; | ||||
| 	const struct dm_deps *deps; | ||||
| 	struct dm_info info; | ||||
| 	int major, minor; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!dm_task_set_name(dmt, name)) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!dm_task_no_open_count(dmt)) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!dm_task_run(dmt)) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!dm_task_get_info(dmt, &info)) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!(deps = dm_task_get_deps(dmt))) | ||||
| 		goto out; | ||||
|  | ||||
| 	if (!info.exists || deps->count != 1) | ||||
| 		goto out; | ||||
|  | ||||
| 	major = (int) MAJOR(deps->device[0]); | ||||
| 	minor = (int) MINOR(deps->device[0]); | ||||
| 	if ((major != tp_major) || (minor != tp_minor)) | ||||
| 		goto out; | ||||
|  | ||||
| 	*dev_minor = info.minor; | ||||
|  | ||||
| #if THIN_DEBUG | ||||
| 	{ | ||||
| 		char dev_name[PATH_MAX]; | ||||
| 		if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name))) | ||||
| 			syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s", | ||||
| 			       name, major, *dev_minor, dev_name); | ||||
| 	} | ||||
| #endif | ||||
| 	r = 1; | ||||
| out: | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* Get all active devices */ | ||||
| static int _find_all_devs(dm_bitset_t bs, int tp_major, int tp_minor) | ||||
| { | ||||
| 	struct dm_task *dmt; | ||||
| 	struct dm_names *names; | ||||
| 	unsigned next = 0; | ||||
| 	int minor, r = 1; | ||||
|  | ||||
| 	if (!(dmt = dm_task_create(DM_DEVICE_LIST))) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (!dm_task_run(dmt)) { | ||||
| 		r = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!(names = dm_task_get_names(dmt))) { | ||||
| 		r = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!names->dev) | ||||
| 		goto out; | ||||
|  | ||||
| 	do { | ||||
| 		names = (struct dm_names *)((char *) names + next); | ||||
| 		if (_has_deps(names->name, tp_major, tp_minor, &minor)) | ||||
| 			dm_bit_set(bs, minor); | ||||
| 		next = names->next; | ||||
| 	} while (next); | ||||
|  | ||||
| out: | ||||
| 	dm_task_destroy(dmt); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static int _extend(struct dso_state *state) | ||||
| { | ||||
| #if THIN_DEBUG | ||||
| 	syslog(LOG_INFO, "dmeventd executes: %s.\n", state->cmd_str); | ||||
| #endif | ||||
| 	return dmeventd_lvm2_run(state->cmd_str); | ||||
| } | ||||
|  | ||||
| static int _run(const char *cmd, ...) | ||||
| { | ||||
| 	va_list ap; | ||||
| 	int argc = 1; /* for argv[0], i.e. cmd */ | ||||
| 	int i = 0; | ||||
| 	const char **argv; | ||||
| 	pid_t pid = fork(); | ||||
| 	int status; | ||||
|  | ||||
| 	if (pid == 0) { /* child */ | ||||
| 		va_start(ap, cmd); | ||||
| 		while (va_arg(ap, const char *)) | ||||
| 			++argc; | ||||
| 		va_end(ap); | ||||
|  | ||||
| 		/* + 1 for the terminating NULL */ | ||||
| 		argv = alloca(sizeof(const char *) * (argc + 1)); | ||||
|  | ||||
| 		argv[0] = cmd; | ||||
|                 va_start(ap, cmd); | ||||
| 		while ((argv[++i] = va_arg(ap, const char *))); | ||||
| 		va_end(ap); | ||||
|  | ||||
| 		execvp(cmd, (char **)argv); | ||||
| 		syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno)); | ||||
| 		exit(127); | ||||
| 	} | ||||
|  | ||||
| 	if (pid > 0) { /* parent */ | ||||
| 		if (waitpid(pid, &status, 0) != pid) | ||||
| 			return 0; /* waitpid failed */ | ||||
| 		if (!WIFEXITED(status) || WEXITSTATUS(status)) | ||||
| 			return 0; /* the child failed */ | ||||
| 	} | ||||
|  | ||||
| 	if (pid < 0) | ||||
| 		return 0; /* fork failed */ | ||||
|  | ||||
| 	return 1; /* all good */ | ||||
| } | ||||
|  | ||||
| struct mountinfo_s { | ||||
| 	struct dm_info info; | ||||
| 	dm_bitset_t minors; /* Bitset for active thin pool minors */ | ||||
| 	const char *device; | ||||
| }; | ||||
|  | ||||
| static int _umount_device(char *buffer, unsigned major, unsigned minor, | ||||
| 			  char *target, void *cb_data) | ||||
| { | ||||
| 	struct mountinfo_s *data = cb_data; | ||||
|  | ||||
| 	if ((major == data->info.major) && dm_bit(data->minors, minor)) { | ||||
| 		syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n", | ||||
| 		       data->device, target); | ||||
| 		if (!_run(UMOUNT_COMMAND, "-fl", target, NULL)) | ||||
| 			syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n", | ||||
| 			       data->device, target, strerror(errno)); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Find all thin pool users and try to umount them. | ||||
|  * TODO: work with read-only thin pool support | ||||
|  */ | ||||
| static void _umount(struct dm_task *dmt, const char *device) | ||||
| { | ||||
| 	/* TODO: Convert to use hash to reduce memory usage */ | ||||
| 	static const size_t MINORS = (1U << 20); /* 20 bit */ | ||||
| 	struct mountinfo_s data = { | ||||
| 		.device = device, | ||||
| 	}; | ||||
|  | ||||
| 	if (!dm_task_get_info(dmt, &data.info)) | ||||
| 		return; | ||||
|  | ||||
| 	dmeventd_lvm2_unlock(); | ||||
|  | ||||
| 	if (!(data.minors = dm_bitset_create(NULL, MINORS))) { | ||||
| 		syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) { | ||||
| 		syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_mountinfo_read(_umount_device, &data)) { | ||||
| 		syslog(LOG_ERR, "Could not parse mountinfo file.\n"); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| out: | ||||
| 	if (data.minors) | ||||
| 		dm_bitset_destroy(data.minors); | ||||
| 	dmeventd_lvm2_lock(); | ||||
| } | ||||
|  | ||||
| void process_event(struct dm_task *dmt, | ||||
| 		   enum dm_event_mask event __attribute__((unused)), | ||||
| 		   void **private) | ||||
| { | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
| 	int percent; | ||||
| 	struct dso_state *state = *private; | ||||
| 	struct dm_status_thin_pool *tps = NULL; | ||||
| 	void *next = NULL; | ||||
| 	uint64_t start, length; | ||||
| 	char *target_type = NULL; | ||||
| 	char *params; | ||||
|  | ||||
| #if 0 | ||||
| 	/* No longer monitoring, waiting for remove */ | ||||
| 	if (!state->meta_percent_check && !state->data_percent_check) | ||||
| 		return; | ||||
| #endif | ||||
| 	dmeventd_lvm2_lock(); | ||||
|  | ||||
| 	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); | ||||
|  | ||||
| 	if (!target_type || (strcmp(target_type, "thin-pool") != 0)) { | ||||
| 		syslog(LOG_ERR, "Invalid target type.\n"); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_get_status_thin_pool(state->mem, params, &tps)) { | ||||
| 		syslog(LOG_ERR, "Failed to parse status.\n"); | ||||
| 		_umount(dmt, device); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| #if THIN_DEBUG | ||||
| 	syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64 | ||||
| 	       " %" PRIu64  " / %" PRIu64 ".\n", state, | ||||
| 	       tps->used_metadata_blocks, tps->total_metadata_blocks, | ||||
| 	       tps->used_data_blocks, tps->total_data_blocks); | ||||
| #endif | ||||
|  | ||||
| 	/* Thin pool size had changed. Clear the threshold. */ | ||||
| 	if (state->known_metadata_size != tps->total_metadata_blocks) { | ||||
| 		state->metadata_percent_check = CHECK_MINIMUM; | ||||
| 		state->known_metadata_size = tps->total_metadata_blocks; | ||||
| 	} | ||||
|  | ||||
| 	if (state->known_data_size != tps->total_data_blocks) { | ||||
| 		state->data_percent_check = CHECK_MINIMUM; | ||||
| 		state->known_data_size = tps->total_data_blocks; | ||||
| 	} | ||||
|  | ||||
| 	percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks; | ||||
| 	if (percent >= state->metadata_percent_check) { | ||||
| 		/* | ||||
| 		 * Usage has raised more than CHECK_STEP since the last | ||||
| 		 * time. Run actions. | ||||
| 		 */ | ||||
| 		state->metadata_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP; | ||||
|  | ||||
| 		/* FIXME: extension of metadata needs to be written! */ | ||||
| 		if (percent >= WARNING_THRESH) /* Print a warning to syslog. */ | ||||
| 			syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n", | ||||
| 			       device, percent); | ||||
| 		 /* Try to extend the metadata, in accord with user-set policies */ | ||||
| 		if (!_extend(state)) { | ||||
| 			syslog(LOG_ERR, "Failed to extend thin metadata %s.\n", | ||||
| 			       device); | ||||
| 			_umount(dmt, device); | ||||
| 		} | ||||
| 		/* FIXME: hmm READ-ONLY switch should happen in error path */ | ||||
| 	} | ||||
|  | ||||
| 	percent = 100 * tps->used_data_blocks / tps->total_data_blocks; | ||||
| 	if (percent >= state->data_percent_check) { | ||||
| 		/* | ||||
| 		 * Usage has raised more than CHECK_STEP since | ||||
| 		 * the last time. Run actions. | ||||
| 		 */ | ||||
| 		state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP; | ||||
|  | ||||
| 		if (percent >= WARNING_THRESH) /* Print a warning to syslog. */ | ||||
| 			syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent); | ||||
| 		/* Try to extend the thin data, in accord with user-set policies */ | ||||
| 		if (!_extend(state)) { | ||||
| 			syslog(LOG_ERR, "Failed to extend thin %s.\n", device); | ||||
| 			state->data_percent_check = 0; | ||||
| 			_umount(dmt, device); | ||||
| 		} | ||||
| 		/* FIXME: hmm READ-ONLY switch should happen in error path */ | ||||
| 	} | ||||
| out: | ||||
| 	if (tps) | ||||
| 		dm_pool_free(state->mem, tps); | ||||
|  | ||||
| 	dmeventd_lvm2_unlock(); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **private) | ||||
| { | ||||
| 	struct dm_pool *statemem = NULL; | ||||
| 	struct dso_state *state; | ||||
|  | ||||
| 	if (!dmeventd_lvm2_init()) | ||||
| 		goto bad; | ||||
|  | ||||
| 	if (!(statemem = dm_pool_create("thin_pool_state", 2048)) || | ||||
| 	    !(state = dm_pool_zalloc(statemem, sizeof(*state))) || | ||||
| 	    !dmeventd_lvm2_command(statemem, state->cmd_str, | ||||
| 				   sizeof(state->cmd_str), | ||||
| 				   "lvextend --use-policies", | ||||
| 				   device)) { | ||||
| 		if (statemem) | ||||
| 			dm_pool_destroy(statemem); | ||||
| 		dmeventd_lvm2_exit(); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	state->mem = statemem; | ||||
| 	state->metadata_percent_check = CHECK_MINIMUM; | ||||
| 	state->data_percent_check = CHECK_MINIMUM; | ||||
| 	*private = state; | ||||
|  | ||||
| 	syslog(LOG_INFO, "Monitoring thin %s.\n", device); | ||||
|  | ||||
| 	return 1; | ||||
| bad: | ||||
| 	syslog(LOG_ERR, "Failed to monitor thin %s.\n", device); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int unregister_device(const char *device, | ||||
| 		      const char *uuid __attribute__((unused)), | ||||
| 		      int major __attribute__((unused)), | ||||
| 		      int minor __attribute__((unused)), | ||||
| 		      void **private) | ||||
| { | ||||
| 	struct dso_state *state = *private; | ||||
|  | ||||
| 	syslog(LOG_INFO, "No longer monitoring thin %s.\n", device); | ||||
| 	dm_pool_destroy(state->mem); | ||||
| 	dmeventd_lvm2_exit(); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1,60 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2011-2012 Red Hat, Inc. | ||||
| # | ||||
| # This file is part of LVM2. | ||||
| # | ||||
| # This copyrighted material is made available to anyone wishing to use, | ||||
| # modify, copy, or redistribute it subject to the terms and conditions | ||||
| # of the GNU Lesser General Public License v.2.1. | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public License | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| SOURCES = lvmetad-core.c | ||||
| SOURCES2 = testclient.c | ||||
|  | ||||
| TARGETS = lvmetad lvmetad-testclient | ||||
|  | ||||
| .PHONY: install_lvmetad | ||||
|  | ||||
| CFLOW_LIST = $(SOURCES) | ||||
| CFLOW_LIST_TARGET = $(LIB_NAME).cflow | ||||
| CFLOW_TARGET = lvmetad | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| INCLUDES += -I$(top_srcdir)/libdaemon/server | ||||
| LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper | ||||
|  | ||||
| LIBS += $(PTHREAD_LIBS) | ||||
|  | ||||
| LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) | ||||
| CLDFLAGS += -L$(top_builddir)/libdaemon/server | ||||
| CFLAGS += $(EXTRA_EXEC_CFLAGS) | ||||
|  | ||||
| lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \ | ||||
| 		    $(top_builddir)/libdaemon/server/libdaemonserver.a | ||||
| 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \ | ||||
| 	$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic | ||||
|  | ||||
| # TODO: No idea. No idea how to test either. | ||||
| #ifneq ("$(CFLOW_CMD)", "") | ||||
| #CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) | ||||
| #-include $(top_builddir)/libdm/libdevmapper.cflow | ||||
| #-include $(top_builddir)/lib/liblvm-internal.cflow | ||||
| #-include $(top_builddir)/lib/liblvm2cmd.cflow | ||||
| #-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow | ||||
| #-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow | ||||
| #endif | ||||
|  | ||||
| install_lvmetad: lvmetad | ||||
| 	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F) | ||||
|  | ||||
| install_lvm2: install_lvmetad | ||||
|  | ||||
| install: install_lvm2 | ||||
| @@ -1,83 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2011-2012 Red Hat, Inc. | ||||
|  * | ||||
|  * This file is part of LVM2. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU Lesser General Public License v.2.1. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_LVMETAD_CLIENT_H | ||||
| #define _LVM_LVMETAD_CLIENT_H | ||||
|  | ||||
| #include "daemon-client.h" | ||||
|  | ||||
| #define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket" | ||||
|  | ||||
| struct volume_group; | ||||
|  | ||||
| /* Different types of replies we may get from lvmetad. */ | ||||
|  | ||||
| typedef struct { | ||||
| 	daemon_reply r; | ||||
| 	const char **uuids; /* NULL terminated array */ | ||||
| } lvmetad_uuidlist; | ||||
|  | ||||
| typedef struct { | ||||
| 	daemon_reply r; | ||||
| 	struct dm_config_tree *cft; | ||||
| } lvmetad_vg; | ||||
|  | ||||
| /* Get a list of VG UUIDs that match a given VG name. */ | ||||
| lvmetad_uuidlist lvmetad_lookup_vgname(daemon_handle h, const char *name); | ||||
|  | ||||
| /* Get the metadata of a single VG, identified by UUID. */ | ||||
| lvmetad_vg lvmetad_get_vg(daemon_handle h, const char *uuid); | ||||
|  | ||||
| /* | ||||
|  * Add and remove PVs on demand. Udev-driven systems will use this interface | ||||
|  * instead of scanning. | ||||
|  */ | ||||
| daemon_reply lvmetad_add_pv(daemon_handle h, const char *pv_uuid, const char *mda_content); | ||||
| daemon_reply lvmetad_remove_pv(daemon_handle h, const char *pv_uuid); | ||||
|  | ||||
| /* Trigger a full disk scan, throwing away all caches. XXX do we eventually want | ||||
|  * this? Probably not yet, anyway. | ||||
|  *     daemon_reply lvmetad_rescan(daemon_handle h); | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Update the version of metadata of a volume group. The VG has to be locked for | ||||
|  * writing for this, and the VG metadata here has to match whatever has been | ||||
|  * written to the disk (under this lock). This initially avoids the requirement | ||||
|  * for lvmetad to write to disk (in later revisions, lvmetad_supersede_vg may | ||||
|  * also do the writing, or we probably add another function to do that). | ||||
|  */ | ||||
| daemon_reply lvmetad_supersede_vg(daemon_handle h, struct volume_group *vg); | ||||
|  | ||||
| /* Wrappers to open/close connection */ | ||||
|  | ||||
| static inline daemon_handle lvmetad_open(const char *socket) | ||||
| { | ||||
| 	daemon_info lvmetad_info = { | ||||
| 		.path = "lvmetad", | ||||
| 		.socket = socket ?: LVMETAD_SOCKET, | ||||
| 		.protocol = "lvmetad", | ||||
| 		.protocol_version = 1, | ||||
| 		.autostart = 0 | ||||
| 	}; | ||||
|  | ||||
| 	return daemon_open(lvmetad_info); | ||||
| } | ||||
|  | ||||
| static inline void lvmetad_close(daemon_handle h) | ||||
| { | ||||
| 	return daemon_close(h); | ||||
| } | ||||
|  | ||||
| #endif | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,16 +0,0 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| export LD_LIBRARY_PATH="$1" | ||||
|  | ||||
| test -n "$2" && { | ||||
|     rm -f /var/run/lvmetad.{socket,pid} | ||||
|     chmod +rx lvmetad | ||||
|     valgrind ./lvmetad -f & | ||||
|     PID=$! | ||||
|     sleep 1 | ||||
|     ./testclient | ||||
|     kill $PID | ||||
|     exit 0 | ||||
| } | ||||
|  | ||||
| sudo ./test.sh "$1" . | ||||
| @@ -1,127 +0,0 @@ | ||||
| #include "lvmetad-client.h" | ||||
| #include "label.h" | ||||
| #include "lvmcache.h" | ||||
| #include "metadata.h" | ||||
|  | ||||
| const char *uuid1 = "abcd-efgh"; | ||||
| const char *uuid2 = "bbcd-efgh"; | ||||
| const char *vgid = "yada-yada"; | ||||
| const char *uuid3 = "cbcd-efgh"; | ||||
|  | ||||
| const char *metadata2 = "{\n" | ||||
| 	"id = \"yada-yada\"\n" | ||||
| 	"seqno = 15\n" | ||||
| 	"status = [\"READ\", \"WRITE\"]\n" | ||||
| 	"flags = []\n" | ||||
| 	"extent_size = 8192\n" | ||||
| 	"physical_volumes {\n" | ||||
| 	"    pv0 {\n" | ||||
| 	"        id = \"abcd-efgh\"\n" | ||||
| 	"    }\n" | ||||
| 	"    pv1 {\n" | ||||
| 	"        id = \"bbcd-efgh\"\n" | ||||
| 	"    }\n" | ||||
| 	"    pv2 {\n" | ||||
| 	"        id = \"cbcd-efgh\"\n" | ||||
| 	"    }\n" | ||||
| 	"}\n" | ||||
| 	"}\n"; | ||||
|  | ||||
| void _handle_reply(daemon_reply reply) { | ||||
| 	const char *repl = daemon_reply_str(reply, "response", NULL); | ||||
| 	const char *status = daemon_reply_str(reply, "status", NULL); | ||||
| 	const char *vgid = daemon_reply_str(reply, "vgid", NULL); | ||||
|  | ||||
| 	fprintf(stderr, "[C] REPLY: %s\n", repl); | ||||
| 	if (!strcmp(repl, "failed")) | ||||
| 		fprintf(stderr, "[C] REASON: %s\n", daemon_reply_str(reply, "reason", "unknown")); | ||||
| 	if (vgid) | ||||
| 		fprintf(stderr, "[C] VGID: %s\n", vgid); | ||||
| 	if (status) | ||||
| 		fprintf(stderr, "[C] STATUS: %s\n", status); | ||||
| 	daemon_reply_destroy(reply); | ||||
| } | ||||
|  | ||||
| void _pv_add(daemon_handle h, const char *uuid, const char *metadata) | ||||
| { | ||||
| 	daemon_reply reply = daemon_send_simple(h, "pv_add", "uuid = %s", uuid, | ||||
| 						             "metadata = %b", metadata, | ||||
| 						             NULL); | ||||
| 	_handle_reply(reply); | ||||
| } | ||||
|  | ||||
| int scan(daemon_handle h, char *fn) { | ||||
| 	struct device *dev = dev_cache_get(fn, NULL); | ||||
|  | ||||
| 	struct label *label; | ||||
| 	if (!label_read(dev, &label, 0)) { | ||||
| 		fprintf(stderr, "[C] no label found on %s\n", fn); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	char uuid[64]; | ||||
| 	id_write_format(dev->pvid, uuid, 64); | ||||
| 	fprintf(stderr, "[C] found PV: %s\n", uuid); | ||||
| 	struct lvmcache_info *info = (struct lvmcache_info *) label->info; | ||||
| 	struct physical_volume pv = { 0, }; | ||||
|  | ||||
| 	if (!(info->fmt->ops->pv_read(info->fmt, dev_name(dev), &pv, 0))) { | ||||
| 		fprintf(stderr, "[C] Failed to read PV %s", dev_name(dev)); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	struct format_instance_ctx fic; | ||||
| 	struct format_instance *fid = info->fmt->ops->create_instance(info->fmt, &fic); | ||||
| 	struct metadata_area *mda; | ||||
| 	struct volume_group *vg = NULL; | ||||
| 	dm_list_iterate_items(mda, &info->mdas) { | ||||
| 		struct volume_group *this = mda->ops->vg_read(fid, "", mda); | ||||
| 		if (this && !vg || this->seqno > vg->seqno) | ||||
| 			vg = this; | ||||
| 	} | ||||
| 	if (vg) { | ||||
| 		char *buf = NULL; | ||||
| 		/* TODO. This is not entirely correct, since export_vg_to_buffer | ||||
| 		 * adds trailing garbage to the buffer. We may need to use | ||||
| 		 * export_vg_to_config_tree and format the buffer ourselves. It | ||||
| 		 * does, however, work for now, since the garbage is well | ||||
| 		 * formatted and has no conflicting keys with the rest of the | ||||
| 		 * request.  */ | ||||
| 		export_vg_to_buffer(vg, &buf); | ||||
| 		daemon_reply reply = | ||||
| 			daemon_send_simple(h, "pv_add", "uuid = %s", uuid, | ||||
| 					      "metadata = %b", strchr(buf, '{'), | ||||
| 					      NULL); | ||||
| 		_handle_reply(reply); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void _dump_vg(daemon_handle h, const char *uuid) | ||||
| { | ||||
| 	daemon_reply reply = daemon_send_simple(h, "vg_by_uuid", "uuid = %s", uuid, NULL); | ||||
| 	fprintf(stderr, "[C] reply buffer: %s\n", reply.buffer); | ||||
| 	daemon_reply_destroy(reply); | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) { | ||||
| 	daemon_handle h = lvmetad_open(); | ||||
|  | ||||
| 	if (argc > 1) { | ||||
| 		int i; | ||||
| 		struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0); | ||||
| 		for (i = 1; i < argc; ++i) { | ||||
| 			const char *uuid = NULL; | ||||
| 			scan(h, argv[i]); | ||||
| 		} | ||||
| 		destroy_toolcontext(cmd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	_pv_add(h, uuid1, NULL); | ||||
| 	_pv_add(h, uuid2, metadata2); | ||||
| 	_dump_vg(h, vgid); | ||||
| 	_pv_add(h, uuid3, NULL); | ||||
|  | ||||
| 	daemon_close(h); | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										6
									
								
								debian/README.Debian
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								debian/README.Debian
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| LVM2 requires the device-mapper kernel module (dm-mod).  This is | ||||
| available as a kernel patch for 2.4 (in kernel-patch-device-mapper), and | ||||
| is distributed with linux 2.5 and above.  The LVM1 kernel module (lvm-mod) | ||||
| will not work with lvm2 packages.  dm-mod and lvm-mod may both be loaded | ||||
| in the kernel at the same time with no problems.  Without dm-mod, this | ||||
| package is pretty useless. | ||||
							
								
								
									
										82
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| lvm2 (1.95.15-1) unstable; urgency=low | ||||
|    | ||||
|   * New upstream release. | ||||
|   * Remove undocumented manpage symlinks. | ||||
|   * Update description to be more informative.  (Closes: #173499) | ||||
|   * Add kernel-patch-device-mapper suggestion. | ||||
|   * Update standards version. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Sun, 16 Feb 2002 04:21:26 -0400 | ||||
|  | ||||
| lvm2 (1.95.11-1) unstable; urgency=low | ||||
|  | ||||
|   * New upstream release.  (Closes: #171436) | ||||
|   * Removed TODO and INTRO from debian/docs; added WHATS_NEW. | ||||
|   * Remove vgcfgrestore.8 undocumented symlink. | ||||
|   * Added a README.Debian, mentioning the device-mapper kernel module | ||||
|     requirement that lvm2 has.  (Closes: #171674, #163020) | ||||
|   * Get rid of debian/conffiles (debhelper's smart enough to figure that out). | ||||
|   * debian/copyright fix to appease lintian. | ||||
|   * Fix typo in tools/commands.h that caused /usr/sbin/; to be created. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Mon,  9 Dec 2002 02:51:02 -0400 | ||||
|  | ||||
| lvm2 (1.95.10-2) unstable; urgency=low | ||||
|  | ||||
|   * Fix software raid problems by ensuring lvm init script runs after | ||||
|     raidtools init script.  (Closes: #152569) | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Tue,  3 Sep 2002 04:05:43 -0400 | ||||
|  | ||||
| lvm2 (1.95.10-1) unstable; urgency=low | ||||
|  | ||||
|   * New upstream release (Beta 3.2). | ||||
|   * Change all references to /dev/device-mapper/control to | ||||
|     /dev/mapper/control. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Sun,  1 Sep 2002 18:55:12 -0400 | ||||
|  | ||||
| lvm2 (0.95.05-3) unstable; urgency=low | ||||
|  | ||||
|   * Get rid of awk dependency in init script.  (Closes: #146257) | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Sun, 12 May 2002 04:39:06 -0500 | ||||
|  | ||||
| lvm2 (0.95.05-2) unstable; urgency=low | ||||
|  | ||||
|   * Use ${shlibs:Depends} in Depends. | ||||
|   * Get rid of postinst/postrm scripts, use debhelper's init script instead. | ||||
|   * Add Conflicts against lvm10, lvm-common. | ||||
|   * Fix endian issues on big-endian machines. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Thu,  2 May 2002 23:53:53 -0500 | ||||
|  | ||||
| lvm2 (0.95.05-1) unstable; urgency=low | ||||
|  | ||||
|   * New release (Beta2). | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Thu, 25 Apr 2002 00:37:41 -0500 | ||||
|  | ||||
| lvm2 (0.95.04cvs20020306-1) unstable; urgency=low | ||||
|  | ||||
|   * CVS updated. | ||||
|   * Convert from debian native package. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Wed,  6 Mar 2002 00:43:21 -0500 | ||||
|  | ||||
| lvm2 (0.95.04cvs20020304) unstable; urgency=low | ||||
|  | ||||
|   * CVS updated. | ||||
|   * Enhance init script; create devmapper control device, etc. | ||||
|   * Add dmsetup as a suggestion. | ||||
|   * Add /etc/lvm/lvm.conf conffile. | ||||
|   * Add undocumented(7) for the commands missing manpages. | ||||
|    | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Mon,  4 Mar 2002 04:51:26 -0500 | ||||
|  | ||||
| lvm2 (0.95.02cvs20020220) unstable; urgency=low | ||||
|  | ||||
|   * Initial Release. | ||||
|  | ||||
|  -- Andres Salomon <dilinger@mp3revolution.net>  Wed, 20 Feb 2002 03:17:25 -0500 | ||||
|  | ||||
							
								
								
									
										24
									
								
								debian/control
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								debian/control
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| Source: lvm2 | ||||
| Section: admin | ||||
| Priority: optional | ||||
| Maintainer: Andres Salomon <dilinger@mp3revolution.net> | ||||
| Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev | ||||
| Standards-Version: 3.5.8.0 | ||||
|  | ||||
| Package: lvm2 | ||||
| Architecture: any | ||||
| Depends: ${shlibs:Depends} | ||||
| Conflicts: lvm10, lvm-common | ||||
| Replaces: lvm10, lvm-common | ||||
| Provides: lvm-binaries | ||||
| Suggests: dmsetup, kernel-patch-device-mapper | ||||
| Description: The Linux Logical Volume Manager | ||||
|  This is LVM2, the rewrite of The Linux Logical Volume Manager.  LVM | ||||
|  supports enterprise level volume management of disk and disk subsystems | ||||
|  by grouping arbitrary disks into volume groups. The total capacity of | ||||
|  volume groups can be allocated to logical volumes, which are accessed as | ||||
|  regular block devices. | ||||
|  . | ||||
|  LVM2 is currently stable, but has some unimplemented features (most notably, | ||||
|  pvmove and e2fsadm).  It is not yet recommended for production use.  It is | ||||
|  backwards-compatible with LVM1 (lvm10), and requires Linux kernel 2.4. | ||||
							
								
								
									
										25
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| This package was debianized by Andres Salomon <dilinger@mp3revolution.net> on | ||||
| Wed, 20 Feb 2002 03:17:25 -0500. | ||||
|  | ||||
| It was downloaded from http://www.sistina.com/products_lvm.htm | ||||
|  | ||||
| Upstream Author: LVM Development Team | ||||
|  | ||||
| Copyright (c) 2001-2002 LVM Development Team | ||||
|  | ||||
| LVM2 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. | ||||
|  | ||||
| LVM2 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, write to the Free Software | ||||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA | ||||
|  | ||||
| On Debian systems, the full text of the GPL can be found in | ||||
| /usr/share/common-licenses/GPL | ||||
							
								
								
									
										4
									
								
								debian/dirs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								debian/dirs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| etc/lvm | ||||
| usr/share/man/man5 | ||||
| usr/share/man/man8 | ||||
| sbin | ||||
							
								
								
									
										5
									
								
								debian/docs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								debian/docs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| BUGS | ||||
| README | ||||
| VERSION | ||||
| WHATS_NEW | ||||
| doc/* | ||||
							
								
								
									
										64
									
								
								debian/init.d
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								debian/init.d
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| #! /bin/sh | ||||
| # | ||||
| # lvm2		This script handles LVM2 initialization/shutdown. | ||||
| # | ||||
| #		Written by Andres Salomon <dilinger@mp3revolution.net>. | ||||
| # | ||||
|  | ||||
| PATH=/sbin:/bin:/usr/sbin:/usr/bin | ||||
| NAME=lvm2 | ||||
| DESC=LVM | ||||
|  | ||||
| test -x /sbin/vgchange || exit 0 | ||||
| modprobe dm-mod >/dev/null 2>&1 | ||||
|  | ||||
| # Create necessary files in /dev for device-mapper | ||||
| create_devfiles() { | ||||
| 	DIR="/dev/mapper" | ||||
| 	FILE="$DIR/control" | ||||
| 	major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//') | ||||
| 	minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//') | ||||
|  | ||||
| 	if test ! -d $DIR; then | ||||
| 		mkdir --mode=755 $DIR >/dev/null 2>&1 | ||||
| 	fi | ||||
|  | ||||
| 	if test ! -c $FILE -a ! -z "$minor"; then | ||||
| 		mknod --mode=600 $FILE c $major $minor >/dev/null 2>&1 | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| case "$1" in | ||||
|   start) | ||||
| 	echo -n "Initializing $DESC: " | ||||
| 	create_devfiles | ||||
| 	vgchange -a y | ||||
|  | ||||
| #	# Mount all LVM devices | ||||
| #	for vg in $( vgchange -a y 2>/dev/null | grep active | awk -F\" '{print $2}' ); do | ||||
| #		MTPT=$( grep $vg /etc/fstab | awk '{print $2}' ) | ||||
| #		mount $MTPT | ||||
| #	done | ||||
| 	echo "$NAME." | ||||
| 	;; | ||||
|   stop) | ||||
| 	echo -n "Shutting down $DESC: " | ||||
| 	# We don't really try all that hard to shut it down; far too many | ||||
| 	# things that can keep it from successfully shutting down. | ||||
| 	vgchange -a n | ||||
| 	echo "$NAME." | ||||
| 	;; | ||||
|   restart|force-reload) | ||||
| 	echo -n "Restarting $DESC: " | ||||
| 	vgchange -a n | ||||
| 	sleep 1 | ||||
| 	vgchange -a y | ||||
| 	echo "$NAME." | ||||
| 	;; | ||||
|   *) | ||||
| 	echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2 | ||||
| 	exit 1 | ||||
| 	;; | ||||
| esac | ||||
|  | ||||
| exit 0 | ||||
							
								
								
									
										26
									
								
								debian/manpages
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								debian/manpages
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| debian/lvm2/usr/share/man/man5/lvm.conf.5 | ||||
| debian/lvm2/usr/share/man/man8/lvchange.8 | ||||
| debian/lvm2/usr/share/man/man8/lvcreate.8 | ||||
| debian/lvm2/usr/share/man/man8/lvdisplay.8 | ||||
| debian/lvm2/usr/share/man/man8/lvextend.8 | ||||
| debian/lvm2/usr/share/man/man8/lvm.8 | ||||
| debian/lvm2/usr/share/man/man8/lvmchange.8 | ||||
| debian/lvm2/usr/share/man/man8/lvreduce.8 | ||||
| debian/lvm2/usr/share/man/man8/lvremove.8 | ||||
| debian/lvm2/usr/share/man/man8/lvrename.8 | ||||
| debian/lvm2/usr/share/man/man8/lvscan.8 | ||||
| debian/lvm2/usr/share/man/man8/pvchange.8 | ||||
| debian/lvm2/usr/share/man/man8/pvcreate.8 | ||||
| debian/lvm2/usr/share/man/man8/pvdisplay.8 | ||||
| debian/lvm2/usr/share/man/man8/pvscan.8 | ||||
| debian/lvm2/usr/share/man/man8/vgcfgbackup.8 | ||||
| debian/lvm2/usr/share/man/man8/vgchange.8 | ||||
| debian/lvm2/usr/share/man/man8/vgck.8 | ||||
| debian/lvm2/usr/share/man/man8/vgcreate.8 | ||||
| debian/lvm2/usr/share/man/man8/vgdisplay.8 | ||||
| debian/lvm2/usr/share/man/man8/vgextend.8 | ||||
| debian/lvm2/usr/share/man/man8/vgmerge.8 | ||||
| debian/lvm2/usr/share/man/man8/vgreduce.8 | ||||
| debian/lvm2/usr/share/man/man8/vgremove.8 | ||||
| debian/lvm2/usr/share/man/man8/vgrename.8 | ||||
| debian/lvm2/usr/share/man/man8/vgscan.8 | ||||
							
								
								
									
										119
									
								
								debian/rules
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										119
									
								
								debian/rules
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| #!/usr/bin/make -f | ||||
| # Sample debian/rules that uses debhelper.  | ||||
| # GNU copyright 1997 by Joey Hess. | ||||
| # | ||||
| # This version is for a hypothetical package that builds an | ||||
| # architecture-dependant package, as well as an architecture-independent | ||||
| # package. | ||||
|  | ||||
| # Uncomment this to turn on verbose mode.  | ||||
| #export DH_VERBOSE=1 | ||||
|  | ||||
| # This is the debhelper compatibility version to use. | ||||
| export DH_COMPAT=3 | ||||
|  | ||||
| # These are used for cross-compiling and for saving the configure script | ||||
| # from having to guess our platform (since we know it already) | ||||
| DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) | ||||
| DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) | ||||
|  | ||||
| ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) | ||||
| 	CFLAGS += -g | ||||
| endif | ||||
| ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) | ||||
| 	INSTALL_PROGRAM += -s | ||||
| endif | ||||
|  | ||||
| configure: configure-stamp | ||||
| configure-stamp: | ||||
| 	dh_testdir | ||||
| 	# Add here commands to configure the package. | ||||
| 	./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/ --mandir=\$${prefix}/usr/share/man --infodir=\$${prefix}/usr/share/info | ||||
|  | ||||
| 	touch configure-stamp | ||||
|  | ||||
| build-arch: configure-stamp build-arch-stamp | ||||
| build-arch-stamp: | ||||
| 	dh_testdir | ||||
|  | ||||
| 	# Add here command to compile/build the package. | ||||
| 	$(MAKE) | ||||
|  | ||||
| 	touch build-arch-stamp | ||||
|  | ||||
| build-indep: configure-stamp build-indep-stamp | ||||
| build-indep-stamp: | ||||
| 	dh_testdir | ||||
|  | ||||
| 	# Add here command to compile/build the arch indep package. | ||||
| 	# It's ok not to do anything here, if you don't need to build | ||||
| 	#  anything for this package. | ||||
| 	#/usr/bin/docbook-to-man debian/lvm2.sgml > lvm2.1 | ||||
|  | ||||
| 	touch build-indep-stamp | ||||
|  | ||||
| build: build-arch build-indep | ||||
|  | ||||
| clean: | ||||
| 	dh_testdir | ||||
| 	dh_testroot | ||||
| 	rm -f build-stamp configure-stamp | ||||
|  | ||||
| 	# Add here commands to clean up after the build process. | ||||
| 	-$(MAKE) distclean | ||||
| 	-test -r /usr/share/misc/config.sub && \ | ||||
| 	  cp -f /usr/share/misc/config.sub config.sub | ||||
| 	-test -r /usr/share/misc/config.guess && \ | ||||
| 	  cp -f /usr/share/misc/config.guess config.guess | ||||
|  | ||||
|  | ||||
| 	dh_clean | ||||
|  | ||||
| install: DH_OPTIONS= | ||||
| install: build | ||||
| 	dh_testdir | ||||
| 	dh_testroot | ||||
| 	dh_clean -k | ||||
| 	dh_installdirs | ||||
|  | ||||
| 	# Add here commands to install the package into debian/lvm2. | ||||
| 	$(MAKE) install prefix=$(CURDIR)/debian/lvm2 | ||||
| 	install -m 0644 doc/example.conf debian/lvm2/etc/lvm/lvm.conf | ||||
|  | ||||
|  | ||||
| # Build architecture-independent files here. | ||||
| # Pass -i to all debhelper commands in this target to reduce clutter. | ||||
| binary-indep: build install | ||||
| # nada. | ||||
|  | ||||
| # Build architecture-dependent files here. | ||||
| binary-arch: build install | ||||
| 	dh_testdir | ||||
| 	dh_testroot | ||||
|  | ||||
| #	dh_installdebconf | ||||
| 	dh_installdocs | ||||
| 	dh_installexamples | ||||
| #	dh_installlogrotate -a | ||||
| #	dh_installemacsen -a | ||||
| #	dh_installpam -a | ||||
| #	dh_installmime -a | ||||
| 	dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ." | ||||
| 	dh_installcron | ||||
| 	dh_installman | ||||
| 	dh_installinfo  | ||||
| 	dh_installchangelogs | ||||
| 	dh_strip | ||||
| 	dh_link | ||||
| 	dh_compress | ||||
| 	dh_fixperms | ||||
| 	dh_makeshlibs | ||||
| 	dh_installdeb | ||||
| #	dh_perl -a | ||||
| 	dh_shlibdeps | ||||
| 	dh_gencontrol | ||||
| 	dh_md5sums | ||||
| 	dh_builddeb | ||||
|  | ||||
| binary: binary-indep binary-arch | ||||
| .PHONY: build clean binary-indep binary-arch binary install configure | ||||
							
								
								
									
										1
									
								
								doc/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								doc/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| example.conf | ||||
| @@ -1,7 +1,7 @@ | ||||
| #
 | ||||
| # Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 | ||||
| # Copyright (C) 2004 Red Hat, Inc. All rights reserved.
 | ||||
| #
 | ||||
| # This file is part of LVM2.
 | ||||
| # This file is part of the LVM2.
 | ||||
| #
 | ||||
| # This copyrighted material is made available to anyone wishing to use,
 | ||||
| # modify, copy, or redistribute it subject to the terms and conditions
 | ||||
| @@ -13,19 +13,17 @@ | ||||
| 
 | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
| VPATH = @srcdir@ | ||||
| 
 | ||||
| .PHONY: client server | ||||
| CONFSRC=example.conf | ||||
| CONFDEST=lvm.conf | ||||
| 
 | ||||
| SUBDIRS += client | ||||
| include ../make.tmpl | ||||
| 
 | ||||
| ifeq ("@BUILD_LVMETAD@", "yes") | ||||
|   SUBDIRS += server | ||||
| server: client | ||||
| endif | ||||
| install: | ||||
| 	@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
 | ||||
| 		echo "Installing $(CONFSRC) as $(confdir)/$(CONFDEST)"; \
 | ||||
| 		@INSTALL@ -D $(OWNER) $(GROUP) -m 644 $(CONFSRC) \
 | ||||
| 			$(confdir)/$(CONFDEST); \
 | ||||
| 	fi | ||||
| 
 | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = client server | ||||
| endif | ||||
| 
 | ||||
| include $(top_builddir)/make.tmpl | ||||
							
								
								
									
										283
									
								
								doc/example.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								doc/example.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,283 @@ | ||||
| # This is an example configuration file for the LVM2 system. | ||||
| # It contains the default settings that would be used if there was no | ||||
| # /etc/lvm/lvm.conf file. | ||||
| # | ||||
| # Refer to 'man lvm.conf' for further information including the file layout. | ||||
| # | ||||
| # To put this file in a different directory and override /etc/lvm set | ||||
| # the environment variable LVM_SYSTEM_DIR before running the tools. | ||||
|  | ||||
|  | ||||
| # This section allows you to configure which block devices should | ||||
| # be used by the LVM system. | ||||
| devices { | ||||
|  | ||||
|     # Where do you want your volume groups to appear ? | ||||
|     dir = "/dev" | ||||
|  | ||||
|     # An array of directories that contain the device nodes you wish | ||||
|     # to use with LVM2. | ||||
|     scan = [ "/dev" ] | ||||
|  | ||||
|     # A filter that tells LVM2 to only use a restricted set of devices. | ||||
|     # The filter consists of an array of regular expressions.  These | ||||
|     # expressions can be delimited by a character of your choice, and | ||||
|     # prefixed with either an 'a' (for accept) or 'r' (for reject). | ||||
|     # The first expression found to match a device name determines if | ||||
|     # the device will be accepted or rejected (ignored).  Devices that | ||||
|     # don't match any patterns are accepted. | ||||
|  | ||||
|     # Remember to run vgscan after you change this parameter to ensure  | ||||
|     # that the cache file gets regenerated (see below). | ||||
|  | ||||
|     # By default we accept every block device: | ||||
|     filter = [ "a/.*/" ] | ||||
|  | ||||
|     # Exclude the cdrom drive | ||||
|     # filter = [ "r|/dev/cdrom|" ] | ||||
|  | ||||
|     # When testing I like to work with just loopback devices: | ||||
|     # filter = [ "a/loop/", "r/.*/" ] | ||||
|  | ||||
|     # Or maybe all loops and ide drives except hdc: | ||||
|     # filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ] | ||||
|  | ||||
|     # Use anchors if you want to be really specific | ||||
|     # filter = [ "a|^/dev/hda8$|", "r/.*/" ] | ||||
|  | ||||
|     # The results of the filtering are cached on disk to avoid | ||||
|     # rescanning dud devices (which can take a very long time).  By | ||||
|     # default this cache file is hidden in the /etc/lvm directory. | ||||
|     # It is safe to delete this file: the tools regenerate it. | ||||
|     cache = "/etc/lvm/.cache" | ||||
|  | ||||
|     # You can turn off writing this cache file by setting this to 0. | ||||
|     write_cache_state = 1 | ||||
|  | ||||
|     # Advanced settings. | ||||
|  | ||||
|     # List of pairs of additional acceptable block device types found  | ||||
|     # in /proc/devices with maximum (non-zero) number of partitions. | ||||
|     # types = [ "fd", 16 ] | ||||
|  | ||||
|     # If sysfs is mounted (2.6 kernels) restrict device scanning to  | ||||
|     # the block devices it believes are valid. | ||||
|     # 1 enables; 0 disables. | ||||
|     sysfs_scan = 1	 | ||||
|  | ||||
|     # By default, LVM2 will ignore devices used as components of | ||||
|     # software RAID (md) devices by looking for md superblocks. | ||||
|     # 1 enables; 0 disables. | ||||
|     md_component_detection = 1 | ||||
| } | ||||
|  | ||||
| # This section that allows you to configure the nature of the | ||||
| # information that LVM2 reports. | ||||
| log { | ||||
|  | ||||
|     # Controls the messages sent to stdout or stderr. | ||||
|     # There are three levels of verbosity, 3 being the most verbose. | ||||
|     verbose = 0 | ||||
|  | ||||
|     # Should we send log messages through syslog? | ||||
|     # 1 is yes; 0 is no. | ||||
|     syslog = 1 | ||||
|  | ||||
|     # Should we log error and debug messages to a file? | ||||
|     # By default there is no log file. | ||||
|     #file = "/var/log/lvm2.log" | ||||
|  | ||||
|     # Should we overwrite the log file each time the program is run? | ||||
|     # By default we append. | ||||
|     overwrite = 0 | ||||
|  | ||||
|     # What level of log messages should we send to the log file and/or syslog? | ||||
|     # There are 6 syslog-like log levels currently in use - 2 to 7 inclusive. | ||||
|     # 7 is the most verbose (LOG_DEBUG). | ||||
|     level = 0 | ||||
|      | ||||
|     # Format of output messages | ||||
|     # Whether or not (1 or 0) to indent messages according to their severity | ||||
|     indent = 1 | ||||
|  | ||||
|     # Whether or not (1 or 0) to display the command name on each line output | ||||
|     command_names = 0 | ||||
|  | ||||
|     # A prefix to use before the message text (but after the command name, | ||||
|     # if selected).  Default is two spaces, so you can see/grep the severity | ||||
|     # of each message. | ||||
|     prefix = "  " | ||||
|  | ||||
|     # To make the messages look similar to the original LVM tools use: | ||||
|     #   indent = 0 | ||||
|     #   command_names = 1 | ||||
|     #   prefix = " -- " | ||||
|  | ||||
|     # Set this if you want log messages during activation. | ||||
|     # Don't use this in low memory situations (can deadlock). | ||||
|     # activation = 0 | ||||
| } | ||||
|  | ||||
| # Configuration of metadata backups and archiving.  In LVM2 when we | ||||
| # talk about a 'backup' we mean making a copy of the metadata for the | ||||
| # *current* system.  The 'archive' contains old metadata configurations. | ||||
| # Backups are stored in a human readeable text format. | ||||
| backup { | ||||
|  | ||||
|     # Should we maintain a backup of the current metadata configuration ? | ||||
|     # Use 1 for Yes; 0 for No. | ||||
|     # Think very hard before turning this off! | ||||
|     backup = 1 | ||||
|  | ||||
|     # Where shall we keep it ? | ||||
|     # Remember to back up this directory regularly! | ||||
|     backup_dir = "/etc/lvm/backup" | ||||
|  | ||||
|     # Should we maintain an archive of old metadata configurations. | ||||
|     # Use 1 for Yes; 0 for No. | ||||
|     # On by default.  Think very hard before turning this off. | ||||
|     archive = 1 | ||||
|  | ||||
|     # Where should archived files go ? | ||||
|     # Remember to back up this directory regularly! | ||||
|     archive_dir = "/etc/lvm/archive" | ||||
|      | ||||
|     # What is the minimum number of archive files you wish to keep ? | ||||
|     retain_min = 10 | ||||
|  | ||||
|     # What is the minimum time you wish to keep an archive file for ? | ||||
|     retain_days = 30 | ||||
| } | ||||
|  | ||||
| # Settings for the running LVM2 in shell (readline) mode. | ||||
| shell { | ||||
|  | ||||
|     # Number of lines of history to store in ~/.lvm_history | ||||
|     history_size = 100 | ||||
| } | ||||
|  | ||||
|  | ||||
| # Miscellaneous global LVM2 settings | ||||
| global { | ||||
|      | ||||
|     # The file creation mask for any files and directories created. | ||||
|     # Interpreted as octal if the first digit is zero. | ||||
|     umask = 077 | ||||
|  | ||||
|     # Allow other users to read the files | ||||
|     #umask = 022 | ||||
|  | ||||
|     # Enabling test mode means that no changes to the on disk metadata | ||||
|     # will be made.  Equivalent to having the -t option on every | ||||
|     # command.  Defaults to off. | ||||
|     test = 0 | ||||
|  | ||||
|     # Whether or not to communicate with the kernel device-mapper. | ||||
|     # Set to 0 if you want to use the tools to manipulate LVM metadata  | ||||
|     # without activating any logical volumes. | ||||
|     # If the device-mapper kernel driver is not present in your kernel | ||||
|     # setting this to 0 should suppress the error messages. | ||||
|     activation = 1 | ||||
|  | ||||
|     # If we can't communicate with device-mapper, should we try running  | ||||
|     # the LVM1 tools? | ||||
|     # This option only applies to 2.4 kernels and is provided to help you | ||||
|     # switch between device-mapper kernels and LVM1 kernels. | ||||
|     # The LVM1 tools need to be installed with .lvm1 suffices | ||||
|     # e.g. vgscan.lvm1 and they will stop working after you start using | ||||
|     # the new lvm2 on-disk metadata format. | ||||
|     # The default value is set when the tools are built. | ||||
|     # fallback_to_lvm1 = 0 | ||||
|  | ||||
|     # The default metadata format that commands should use - "lvm1" or "lvm2". | ||||
|     # The command line override is -M1 or -M2. | ||||
|     # Defaults to "lvm1" if compiled in, else "lvm2". | ||||
|     # format = "lvm1" | ||||
|  | ||||
|     # Location of proc filesystem | ||||
|     proc = "/proc" | ||||
|  | ||||
|     # Type of locking to use. Defaults to file-based locking (1). | ||||
|     # Turn locking off by setting to 0 (dangerous: risks metadata corruption | ||||
|     # if LVM2 commands get run concurrently). | ||||
|     locking_type = 1 | ||||
|  | ||||
|     # Local non-LV directory that holds file-based locks while commands are | ||||
|     # in progress.  A directory like /tmp that may get wiped on reboot is OK. | ||||
|     locking_dir = "/var/lock/lvm" | ||||
|  | ||||
|     # Other entries can go here to allow you to load shared libraries | ||||
|     # e.g. if support for LVM1 metadata was compiled as a shared library use | ||||
|     #   format_libraries = "liblvm2format1.so"  | ||||
|     # Full pathnames can be given. | ||||
|  | ||||
|     # Search this directory first for shared libraries. | ||||
|     #   library_dir = "/lib" | ||||
| } | ||||
|  | ||||
| activation { | ||||
|     # Device used in place of missing stripes if activating incomplete volume. | ||||
|     # For now, you need to set this up yourself first (e.g. with 'dmsetup') | ||||
|     # For example, you could make it return I/O errors using the 'error'  | ||||
|     # target or make it return zeros. | ||||
|     missing_stripe_filler = "/dev/ioerror" | ||||
|  | ||||
|     # Size (in KB) of each copy operation when mirroring | ||||
|     mirror_region_size = 512 | ||||
|  | ||||
|     # How much stack (in KB) to reserve for use while devices suspended | ||||
|     reserved_stack = 256 | ||||
|  | ||||
|     # How much memory (in KB) to reserve for use while devices suspended | ||||
|     reserved_memory = 8192 | ||||
|  | ||||
|     # Nice value used while devices suspended | ||||
|     process_priority = -18 | ||||
|  | ||||
|     # If volume_list is defined, each LV is only activated if there is a | ||||
|     # match against the list. | ||||
|     #   "vgname" and "vgname/lvname" are matched exactly. | ||||
|     #   "@tag" matches any tag set in the LV or VG. | ||||
|     #   "@*" matches if any tag defined on the host is also set in the LV or VG | ||||
|     # | ||||
|     # volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ] | ||||
| } | ||||
|  | ||||
|  | ||||
| #################### | ||||
| # Advanced section # | ||||
| #################### | ||||
|  | ||||
| # Metadata settings | ||||
| # | ||||
| # metadata { | ||||
|     # Default number of copies of metadata to hold on each PV.  0, 1 or 2. | ||||
|     # It's best to leave this at 2. | ||||
|     # You might want to override it from the command line with 0 or 1  | ||||
|     # when running pvcreate on new PVs which are to be added to large VGs. | ||||
|  | ||||
|     # pvmetadatacopies = 2 | ||||
|  | ||||
|     # Approximate default size of on-disk metadata areas in sectors. | ||||
|     # You should increase this if you have large volume groups or | ||||
|     # you want to retain a large on-disk history of your metadata changes. | ||||
|  | ||||
|     # pvmetadatasize = 255 | ||||
|  | ||||
|     # List of directories holding live copies of text format metadata. | ||||
|     # These directories must not be on logical volumes! | ||||
|     # It's possible to use LVM2 with a couple of directories here, | ||||
|     # preferably on different (non-LV) filesystems, and with no other  | ||||
|     # on-disk metadata (pvmetadatacopies = 0). Or this can be in | ||||
|     # addition to on-disk metadata areas. | ||||
|     # The feature was originally added to simplify testing and is not | ||||
|     # supported under low memory situations - the machine could lock up. | ||||
|     # | ||||
|     # Never edit any files in these directories by hand unless you | ||||
|     # you are absolutely sure you know what you are doing! Use | ||||
|     # the supplied toolset to make changes (e.g. vgcfgrestore). | ||||
|  | ||||
|     # dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ] | ||||
| #} | ||||
|  | ||||
|  | ||||
| @@ -13,11 +13,9 @@ | ||||
|  */ | ||||
|  | ||||
| #include "lvm2cmd.h" | ||||
| #include <stdio.h> | ||||
|  | ||||
| /* All output gets passed to this function line-by-line */ | ||||
| void test_log_fn(int level, const char *file, int line, | ||||
| 		 int dm_errno, const char *format) | ||||
| void test_log_fn(int level, const char *file, int line, const char *format) | ||||
| { | ||||
| 	/* Extract and process output here rather than printing it */ | ||||
|  | ||||
|   | ||||
| @@ -1,77 +0,0 @@ | ||||
| Guidance for writing policies | ||||
| ============================= | ||||
|  | ||||
| Try to keep transactionality out of it.  The core is careful to | ||||
| avoid asking about anything that is migrating.  This is a pain, but | ||||
| makes it easier to write the policies. | ||||
|  | ||||
| Mappings are loaded into the policy at construction time. | ||||
|  | ||||
| Every bio that is mapped by the target is referred to the policy. | ||||
| The policy can return a simple HIT or MISS or issue a migration. | ||||
|  | ||||
| Currently there's no way for the policy to issue background work, | ||||
| e.g. to start writing back dirty blocks that are going to be evicte | ||||
| soon. | ||||
|  | ||||
| Because we map bios, rather than requests it's easy for the policy | ||||
| to get fooled by many small bios.  For this reason the core target | ||||
| issues periodic ticks to the policy.  It's suggested that the policy | ||||
| doesn't update states (eg, hit counts) for a block more than once | ||||
| for each tick.  The core ticks by watching bios complete, and so | ||||
| trying to see when the io scheduler has let the ios run. | ||||
|  | ||||
|  | ||||
| Overview of supplied cache replacement policies | ||||
| =============================================== | ||||
|  | ||||
| multiqueue | ||||
| ---------- | ||||
|  | ||||
| This policy is the default. | ||||
|  | ||||
| The multiqueue policy has two sets of 16 queues: one set for entries | ||||
| waiting for the cache and another one for those in the cache. | ||||
| Cache entries in the queues are aged based on logical time. Entry into | ||||
| the cache is based on variable thresholds and queue selection is based | ||||
| on hit count on entry. The policy aims to take different cache miss | ||||
| costs into account and to adjust to varying load patterns automatically. | ||||
|  | ||||
| Message and constructor argument pairs are: | ||||
| 	'sequential_threshold <#nr_sequential_ios>' and | ||||
| 	'random_threshold <#nr_random_ios>'. | ||||
|  | ||||
| The sequential threshold indicates the number of contiguous I/Os | ||||
| required before a stream is treated as sequential.  The random threshold | ||||
| is the number of intervening non-contiguous I/Os that must be seen | ||||
| before the stream is treated as random again. | ||||
|  | ||||
| The sequential and random thresholds default to 512 and 4 respectively. | ||||
|  | ||||
| Large, sequential ios are probably better left on the origin device | ||||
| since spindles tend to have good bandwidth. The io_tracker counts | ||||
| contiguous I/Os to try to spot when the io is in one of these sequential | ||||
| modes. | ||||
|  | ||||
| cleaner | ||||
| ------- | ||||
|  | ||||
| The cleaner writes back all dirty blocks in a cache to decommission it. | ||||
|  | ||||
| Examples | ||||
| ======== | ||||
|  | ||||
| The syntax for a table is: | ||||
| 	cache <metadata dev> <cache dev> <origin dev> <block size> | ||||
| 	<#feature_args> [<feature arg>]* | ||||
| 	<policy> <#policy_args> [<policy arg>]* | ||||
|  | ||||
| The syntax to send a message using the dmsetup command is: | ||||
| 	dmsetup message <mapped device> 0 sequential_threshold 1024 | ||||
| 	dmsetup message <mapped device> 0 random_threshold 8 | ||||
|  | ||||
| Using dmsetup: | ||||
| 	dmsetup create blah --table "0 268435456 cache /dev/sdb /dev/sdc \ | ||||
| 	    /dev/sdd 512 0 mq 4 sequential_threshold 1024 random_threshold 8" | ||||
| 	creates a 128GB large mapped device named 'blah' with the | ||||
| 	sequential threshold set to 1024 and the random_threshold set to 8. | ||||
| @@ -1,243 +0,0 @@ | ||||
| Introduction | ||||
| ============ | ||||
|  | ||||
| dm-cache is a device mapper target written by Joe Thornber, Heinz | ||||
| Mauelshagen, and Mike Snitzer. | ||||
|  | ||||
| It aims to improve performance of a block device (eg, a spindle) by | ||||
| dynamically migrating some of its data to a faster, smaller device | ||||
| (eg, an SSD). | ||||
|  | ||||
| This device-mapper solution allows us to insert this caching at | ||||
| different levels of the dm stack, for instance above the data device for | ||||
| a thin-provisioning pool.  Caching solutions that are integrated more | ||||
| closely with the virtual memory system should give better performance. | ||||
|  | ||||
| The target reuses the metadata library used in the thin-provisioning | ||||
| library. | ||||
|  | ||||
| The decision as to what data to migrate and when is left to a plug-in | ||||
| policy module.  Several of these have been written as we experiment, | ||||
| and we hope other people will contribute others for specific io | ||||
| scenarios (eg. a vm image server). | ||||
|  | ||||
| Glossary | ||||
| ======== | ||||
|  | ||||
|   Migration -  Movement of the primary copy of a logical block from one | ||||
| 	       device to the other. | ||||
|   Promotion -  Migration from slow device to fast device. | ||||
|   Demotion  -  Migration from fast device to slow device. | ||||
|  | ||||
| The origin device always contains a copy of the logical block, which | ||||
| may be out of date or kept in sync with the copy on the cache device | ||||
| (depending on policy). | ||||
|  | ||||
| Design | ||||
| ====== | ||||
|  | ||||
| Sub-devices | ||||
| ----------- | ||||
|  | ||||
| The target is constructed by passing three devices to it (along with | ||||
| other parameters detailed later): | ||||
|  | ||||
| 1. An origin device - the big, slow one. | ||||
|  | ||||
| 2. A cache device - the small, fast one. | ||||
|  | ||||
| 3. A small metadata device - records which blocks are in the cache, | ||||
|    which are dirty, and extra hints for use by the policy object. | ||||
|    This information could be put on the cache device, but having it | ||||
|    separate allows the volume manager to configure it differently, | ||||
|    e.g. as a mirror for extra robustness. | ||||
|  | ||||
| Fixed block size | ||||
| ---------------- | ||||
|  | ||||
| The origin is divided up into blocks of a fixed size.  This block size | ||||
| is configurable when you first create the cache.  Typically we've been | ||||
| using block sizes of 256k - 1024k. | ||||
|  | ||||
| Having a fixed block size simplifies the target a lot.  But it is | ||||
| something of a compromise.  For instance, a small part of a block may be | ||||
| getting hit a lot, yet the whole block will be promoted to the cache. | ||||
| So large block sizes are bad because they waste cache space.  And small | ||||
| block sizes are bad because they increase the amount of metadata (both | ||||
| in core and on disk). | ||||
|  | ||||
| Writeback/writethrough | ||||
| ---------------------- | ||||
|  | ||||
| The cache has two modes, writeback and writethrough. | ||||
|  | ||||
| If writeback, the default, is selected then a write to a block that is | ||||
| cached will go only to the cache and the block will be marked dirty in | ||||
| the metadata. | ||||
|  | ||||
| If writethrough is selected then a write to a cached block will not | ||||
| complete until it has hit both the origin and cache devices.  Clean | ||||
| blocks should remain clean. | ||||
|  | ||||
| A simple cleaner policy is provided, which will clean (write back) all | ||||
| dirty blocks in a cache.  Useful for decommissioning a cache. | ||||
|  | ||||
| Migration throttling | ||||
| -------------------- | ||||
|  | ||||
| Migrating data between the origin and cache device uses bandwidth. | ||||
| The user can set a throttle to prevent more than a certain amount of | ||||
| migration occuring at any one time.  Currently we're not taking any | ||||
| account of normal io traffic going to the devices.  More work needs | ||||
| doing here to avoid migrating during those peak io moments. | ||||
|  | ||||
| For the time being, a message "migration_threshold <#sectors>" | ||||
| can be used to set the maximum number of sectors being migrated, | ||||
| the default being 204800 sectors (or 100MB). | ||||
|  | ||||
| Updating on-disk metadata | ||||
| ------------------------- | ||||
|  | ||||
| On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is | ||||
| written.  If no such requests are made then commits will occur every | ||||
| second.  This means the cache behaves like a physical disk that has a | ||||
| write cache (the same is true of the thin-provisioning target).  If | ||||
| power is lost you may lose some recent writes.  The metadata should | ||||
| always be consistent in spite of any crash. | ||||
|  | ||||
| The 'dirty' state for a cache block changes far too frequently for us | ||||
| to keep updating it on the fly.  So we treat it as a hint.  In normal | ||||
| operation it will be written when the dm device is suspended.  If the | ||||
| system crashes all cache blocks will be assumed dirty when restarted. | ||||
|  | ||||
| Per-block policy hints | ||||
| ---------------------- | ||||
|  | ||||
| Policy plug-ins can store a chunk of data per cache block.  It's up to | ||||
| the policy how big this chunk is, but it should be kept small.  Like the | ||||
| dirty flags this data is lost if there's a crash so a safe fallback | ||||
| value should always be possible. | ||||
|  | ||||
| For instance, the 'mq' policy, which is currently the default policy, | ||||
| uses this facility to store the hit count of the cache blocks.  If | ||||
| there's a crash this information will be lost, which means the cache | ||||
| may be less efficient until those hit counts are regenerated. | ||||
|  | ||||
| Policy hints affect performance, not correctness. | ||||
|  | ||||
| Policy messaging | ||||
| ---------------- | ||||
|  | ||||
| Policies will have different tunables, specific to each one, so we | ||||
| need a generic way of getting and setting these.  Device-mapper | ||||
| messages are used.  Refer to cache-policies.txt. | ||||
|  | ||||
| Discard bitset resolution | ||||
| ------------------------- | ||||
|  | ||||
| We can avoid copying data during migration if we know the block has | ||||
| been discarded.  A prime example of this is when mkfs discards the | ||||
| whole block device.  We store a bitset tracking the discard state of | ||||
| blocks.  However, we allow this bitset to have a different block size | ||||
| from the cache blocks.  This is because we need to track the discard | ||||
| state for all of the origin device (compare with the dirty bitset | ||||
| which is just for the smaller cache device). | ||||
|  | ||||
| Target interface | ||||
| ================ | ||||
|  | ||||
| Constructor | ||||
| ----------- | ||||
|  | ||||
|  cache <metadata dev> <cache dev> <origin dev> <block size> | ||||
|        <#feature args> [<feature arg>]* | ||||
|        <policy> <#policy args> [policy args]* | ||||
|  | ||||
|  metadata dev    : fast device holding the persistent metadata | ||||
|  cache dev	 : fast device holding cached data blocks | ||||
|  origin dev	 : slow device holding original data blocks | ||||
|  block size      : cache unit size in sectors | ||||
|  | ||||
|  #feature args   : number of feature arguments passed | ||||
|  feature args    : writethrough.  (The default is writeback.) | ||||
|  | ||||
|  policy          : the replacement policy to use | ||||
|  #policy args    : an even number of arguments corresponding to | ||||
|                    key/value pairs passed to the policy | ||||
|  policy args     : key/value pairs passed to the policy | ||||
| 		   E.g. 'sequential_threshold 1024' | ||||
| 		   See cache-policies.txt for details. | ||||
|  | ||||
| Optional feature arguments are: | ||||
|    writethrough  : write through caching that prohibits cache block | ||||
| 		   content from being different from origin block content. | ||||
| 		   Without this argument, the default behaviour is to write | ||||
| 		   back cache block contents later for performance reasons, | ||||
| 		   so they may differ from the corresponding origin blocks. | ||||
|  | ||||
| A policy called 'default' is always registered.  This is an alias for | ||||
| the policy we currently think is giving best all round performance. | ||||
|  | ||||
| As the default policy could vary between kernels, if you are relying on | ||||
| the characteristics of a specific policy, always request it by name. | ||||
|  | ||||
| Status | ||||
| ------ | ||||
|  | ||||
| <#used metadata blocks>/<#total metadata blocks> <#read hits> <#read misses> | ||||
| <#write hits> <#write misses> <#demotions> <#promotions> <#blocks in cache> | ||||
| <#dirty> <#features> <features>* <#core args> <core args>* <#policy args> | ||||
| <policy args>* | ||||
|  | ||||
| #used metadata blocks    : Number of metadata blocks used | ||||
| #total metadata blocks   : Total number of metadata blocks | ||||
| #read hits               : Number of times a READ bio has been mapped | ||||
| 			     to the cache | ||||
| #read misses             : Number of times a READ bio has been mapped | ||||
| 			     to the origin | ||||
| #write hits              : Number of times a WRITE bio has been mapped | ||||
| 			     to the cache | ||||
| #write misses            : Number of times a WRITE bio has been | ||||
| 			     mapped to the origin | ||||
| #demotions               : Number of times a block has been removed | ||||
| 			     from the cache | ||||
| #promotions              : Number of times a block has been moved to | ||||
| 			     the cache | ||||
| #blocks in cache         : Number of blocks resident in the cache | ||||
| #dirty                   : Number of blocks in the cache that differ | ||||
| 			     from the origin | ||||
| #feature args            : Number of feature args to follow | ||||
| feature args             : 'writethrough' (optional) | ||||
| #core args               : Number of core arguments (must be even) | ||||
| core args                : Key/value pairs for tuning the core | ||||
| 			     e.g. migration_threshold | ||||
| #policy args             : Number of policy arguments to follow (must be even) | ||||
| policy args              : Key/value pairs | ||||
| 			     e.g. 'sequential_threshold 1024 | ||||
|  | ||||
| Messages | ||||
| -------- | ||||
|  | ||||
| Policies will have different tunables, specific to each one, so we | ||||
| need a generic way of getting and setting these.  Device-mapper | ||||
| messages are used.  (A sysfs interface would also be possible.) | ||||
|  | ||||
| The message format is: | ||||
|  | ||||
|    <key> <value> | ||||
|  | ||||
| E.g. | ||||
|    dmsetup message my_cache 0 sequential_threshold 1024 | ||||
|  | ||||
| Examples | ||||
| ======== | ||||
|  | ||||
| The test suite can be found here: | ||||
|  | ||||
| https://github.com/jthornber/thinp-test-suite | ||||
|  | ||||
| dmsetup create my_cache --table '0 41943040 cache /dev/mapper/metadata \ | ||||
| 	/dev/mapper/ssd /dev/mapper/origin 512 1 writeback default 0' | ||||
| dmsetup create my_cache --table '0 41943040 cache /dev/mapper/metadata \ | ||||
| 	/dev/mapper/ssd /dev/mapper/origin 1024 1 writeback \ | ||||
| 	mq 4 sequential_threshold 1024 random_threshold 8' | ||||
| @@ -1,76 +0,0 @@ | ||||
| dm-crypt | ||||
| ========= | ||||
|  | ||||
| Device-Mapper's "crypt" target provides transparent encryption of block devices | ||||
| using the kernel crypto API. | ||||
|  | ||||
| Parameters: <cipher> <key> <iv_offset> <device path> \ | ||||
| 	      <offset> [<#opt_params> <opt_params>] | ||||
|  | ||||
| <cipher> | ||||
|     Encryption cipher and an optional IV generation mode. | ||||
|     (In format cipher[:keycount]-chainmode-ivopts:ivmode). | ||||
|     Examples: | ||||
|        des | ||||
|        aes-cbc-essiv:sha256 | ||||
|        twofish-ecb | ||||
|  | ||||
|     /proc/crypto contains supported crypto modes | ||||
|  | ||||
| <key> | ||||
|     Key used for encryption. It is encoded as a hexadecimal number. | ||||
|     You can only use key sizes that are valid for the selected cipher. | ||||
|  | ||||
| <keycount> | ||||
|     Multi-key compatibility mode. You can define <keycount> keys and | ||||
|     then sectors are encrypted according to their offsets (sector 0 uses key0; | ||||
|     sector 1 uses key1 etc.).  <keycount> must be a power of two. | ||||
|  | ||||
| <iv_offset> | ||||
|     The IV offset is a sector count that is added to the sector number | ||||
|     before creating the IV. | ||||
|  | ||||
| <device path> | ||||
|     This is the device that is going to be used as backend and contains the | ||||
|     encrypted data.  You can specify it as a path like /dev/xxx or a device | ||||
|     number <major>:<minor>. | ||||
|  | ||||
| <offset> | ||||
|     Starting sector within the device where the encrypted data begins. | ||||
|  | ||||
| <#opt_params> | ||||
|     Number of optional parameters. If there are no optional parameters, | ||||
|     the optional paramaters section can be skipped or #opt_params can be zero. | ||||
|     Otherwise #opt_params is the number of following arguments. | ||||
|  | ||||
|     Example of optional parameters section: | ||||
|         1 allow_discards | ||||
|  | ||||
| allow_discards | ||||
|     Block discard requests (a.k.a. TRIM) are passed through the crypt device. | ||||
|     The default is to ignore discard requests. | ||||
|  | ||||
|     WARNING: Assess the specific security risks carefully before enabling this | ||||
|     option.  For example, allowing discards on encrypted devices may lead to | ||||
|     the leak of information about the ciphertext device (filesystem type, | ||||
|     used space etc.) if the discarded blocks can be located easily on the | ||||
|     device later. | ||||
|  | ||||
| Example scripts | ||||
| =============== | ||||
| LUKS (Linux Unified Key Setup) is now the preferred way to set up disk | ||||
| encryption with dm-crypt using the 'cryptsetup' utility, see | ||||
| http://code.google.com/p/cryptsetup/ | ||||
|  | ||||
| [[ | ||||
| #!/bin/sh | ||||
| # Create a crypt device using dmsetup | ||||
| dmsetup create crypt1 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0" | ||||
| ]] | ||||
|  | ||||
| [[ | ||||
| #!/bin/sh | ||||
| # Create a crypt device using cryptsetup and LUKS header with default cipher | ||||
| cryptsetup luksFormat $1 | ||||
| cryptsetup luksOpen $1 crypt1 | ||||
| ]] | ||||
| @@ -1,26 +0,0 @@ | ||||
| dm-delay | ||||
| ======== | ||||
|  | ||||
| Device-Mapper's "delay" target delays reads and/or writes | ||||
| and maps them to different devices. | ||||
|  | ||||
| Parameters: | ||||
|     <device> <offset> <delay> [<write_device> <write_offset> <write_delay>] | ||||
|  | ||||
| With separate write parameters, the first set is only used for reads. | ||||
| Delays are specified in milliseconds. | ||||
|  | ||||
| Example scripts | ||||
| =============== | ||||
| [[ | ||||
| #!/bin/sh | ||||
| # Create device delaying rw operation for 500ms | ||||
| echo "0 `blockdev --getsize $1` delay $1 0 500" | dmsetup create delayed | ||||
| ]] | ||||
|  | ||||
| [[ | ||||
| #!/bin/sh | ||||
| # Create device delaying only write operation for 500ms and | ||||
| # splitting reads and writes to different devices $1 $2 | ||||
| echo "0 `blockdev --getsize $1` delay $1 0 0 $2 0 500" | dmsetup create delayed | ||||
| ]] | ||||
| @@ -1,53 +0,0 @@ | ||||
| dm-flakey | ||||
| ========= | ||||
|  | ||||
| This target is the same as the linear target except that it exhibits | ||||
| unreliable behaviour periodically.  It's been found useful in simulating | ||||
| failing devices for testing purposes. | ||||
|  | ||||
| Starting from the time the table is loaded, the device is available for | ||||
| <up interval> seconds, then exhibits unreliable behaviour for <down | ||||
| interval> seconds, and then this cycle repeats. | ||||
|  | ||||
| Also, consider using this in combination with the dm-delay target too, | ||||
| which can delay reads and writes and/or send them to different | ||||
| underlying devices. | ||||
|  | ||||
| Table parameters | ||||
| ---------------- | ||||
|   <dev path> <offset> <up interval> <down interval> \ | ||||
|     [<num_features> [<feature arguments>]] | ||||
|  | ||||
| Mandatory parameters: | ||||
|     <dev path>: Full pathname to the underlying block-device, or a | ||||
|                 "major:minor" device-number. | ||||
|     <offset>: Starting sector within the device. | ||||
|     <up interval>: Number of seconds device is available. | ||||
|     <down interval>: Number of seconds device returns errors. | ||||
|  | ||||
| Optional feature parameters: | ||||
|   If no feature parameters are present, during the periods of | ||||
|   unreliability, all I/O returns errors. | ||||
|  | ||||
|   drop_writes: | ||||
| 	All write I/O is silently ignored. | ||||
| 	Read I/O is handled correctly. | ||||
|  | ||||
|   corrupt_bio_byte <Nth_byte> <direction> <value> <flags>: | ||||
| 	During <down interval>, replace <Nth_byte> of the data of | ||||
| 	each matching bio with <value>. | ||||
|  | ||||
|     <Nth_byte>: The offset of the byte to replace. | ||||
| 		Counting starts at 1, to replace the first byte. | ||||
|     <direction>: Either 'r' to corrupt reads or 'w' to corrupt writes. | ||||
| 		 'w' is incompatible with drop_writes. | ||||
|     <value>: The value (from 0-255) to write. | ||||
|     <flags>: Perform the replacement only if bio->bi_rw has all the | ||||
| 	     selected flags set. | ||||
|  | ||||
| Examples: | ||||
|   corrupt_bio_byte 32 r 1 0 | ||||
| 	- replaces the 32nd byte of READ bios with the value 1 | ||||
|  | ||||
|   corrupt_bio_byte 224 w 0 32 | ||||
| 	- replaces the 224th byte of REQ_META (=32) bios with the value 0 | ||||
| @@ -1,75 +0,0 @@ | ||||
| dm-io | ||||
| ===== | ||||
|  | ||||
| Dm-io provides synchronous and asynchronous I/O services. There are three | ||||
| types of I/O services available, and each type has a sync and an async | ||||
| version. | ||||
|  | ||||
| The user must set up an io_region structure to describe the desired location | ||||
| of the I/O. Each io_region indicates a block-device along with the starting | ||||
| sector and size of the region. | ||||
|  | ||||
|    struct io_region { | ||||
|       struct block_device *bdev; | ||||
|       sector_t sector; | ||||
|       sector_t count; | ||||
|    }; | ||||
|  | ||||
| Dm-io can read from one io_region or write to one or more io_regions. Writes | ||||
| to multiple regions are specified by an array of io_region structures. | ||||
|  | ||||
| The first I/O service type takes a list of memory pages as the data buffer for | ||||
| the I/O, along with an offset into the first page. | ||||
|  | ||||
|    struct page_list { | ||||
|       struct page_list *next; | ||||
|       struct page *page; | ||||
|    }; | ||||
|  | ||||
|    int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw, | ||||
|                   struct page_list *pl, unsigned int offset, | ||||
|                   unsigned long *error_bits); | ||||
|    int dm_io_async(unsigned int num_regions, struct io_region *where, int rw, | ||||
|                    struct page_list *pl, unsigned int offset, | ||||
|                    io_notify_fn fn, void *context); | ||||
|  | ||||
| The second I/O service type takes an array of bio vectors as the data buffer | ||||
| for the I/O. This service can be handy if the caller has a pre-assembled bio, | ||||
| but wants to direct different portions of the bio to different devices. | ||||
|  | ||||
|    int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, | ||||
|                        int rw, struct bio_vec *bvec, | ||||
|                        unsigned long *error_bits); | ||||
|    int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, | ||||
|                         int rw, struct bio_vec *bvec, | ||||
|                         io_notify_fn fn, void *context); | ||||
|  | ||||
| The third I/O service type takes a pointer to a vmalloc'd memory buffer as the | ||||
| data buffer for the I/O. This service can be handy if the caller needs to do | ||||
| I/O to a large region but doesn't want to allocate a large number of individual | ||||
| memory pages. | ||||
|  | ||||
|    int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw, | ||||
|                      void *data, unsigned long *error_bits); | ||||
|    int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, | ||||
|                       void *data, io_notify_fn fn, void *context); | ||||
|  | ||||
| Callers of the asynchronous I/O services must include the name of a completion | ||||
| callback routine and a pointer to some context data for the I/O. | ||||
|  | ||||
|    typedef void (*io_notify_fn)(unsigned long error, void *context); | ||||
|  | ||||
| The "error" parameter in this callback, as well as the "*error" parameter in | ||||
| all of the synchronous versions, is a bitset (instead of a simple error value). | ||||
| In the case of an write-I/O to multiple regions, this bitset allows dm-io to | ||||
| indicate success or failure on each individual region. | ||||
|  | ||||
| Before using any of the dm-io services, the user should call dm_io_get() | ||||
| and specify the number of pages they expect to perform I/O on concurrently. | ||||
| Dm-io will attempt to resize its mempool to make sure enough pages are | ||||
| always available in order to avoid unnecessary waiting while performing I/O. | ||||
|  | ||||
| When the user is finished using the dm-io services, they should call | ||||
| dm_io_put() and specify the same number of pages that were given on the | ||||
| dm_io_get() call. | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user