mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-29 16:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			5235 Commits
		
	
	
		
			dev-dct-sc
			...
			v2_02_81
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c7e561d33d | ||
|  | ce94c7ea73 | ||
|  | 6789424259 | ||
|  | 7a18ae6da4 | ||
|  | 5f2829b0a0 | ||
|  | 49376579bf | ||
|  | 8a3e1de5c8 | ||
|  | 6470c383b2 | ||
|  | cbfb6504a8 | ||
|  | a4cdc80836 | ||
|  | b598e9482d | ||
|  | 0c83d60688 | ||
|  | d2a3f3afa1 | ||
|  | f1e5f9d8d5 | ||
|  | 92c39fea53 | ||
|  | d67ac7ed5c | ||
|  | 9e397d92f5 | ||
|  | f40795a119 | ||
|  | 8d4f93634f | ||
|  | c141fe1c44 | ||
|  | 2e776f6b50 | ||
|  | 437dac07eb | ||
|  | 77e3610e1a | ||
|  | a23f91ad2f | ||
|  | 4fef104bf1 | ||
|  | 57f8bc3081 | ||
|  | 40fbdb71bd | ||
|  | 7cbf6fa3a6 | ||
|  | 019423f769 | ||
|  | 4114ac5d22 | ||
|  | 1a2e58b067 | ||
|  | 9ce215ed01 | ||
|  | ad7bccb8ea | ||
|  | 3621b75306 | ||
|  | 14908e3a3b | ||
|  | 7ce032b99d | ||
|  | dcaf6313af | ||
|  | b74d30d55a | ||
|  | 9c705ce71e | ||
|  | 16af1b083b | ||
|  | f4d63e9e58 | ||
|  | cae4882865 | ||
|  | 9d4bb244e3 | ||
|  | 41b1b9487c | ||
|  | 6c1db4a7d6 | ||
|  | 7b0c0103a9 | ||
|  | ef6ec3f737 | ||
|  | 78269c2110 | ||
|  | eb91c54467 | ||
|  | 56b6c12e8a | ||
|  | 6507ce98df | ||
|  | 2fbadde558 | ||
|  | 5a363d74f2 | ||
|  | b2817688ac | ||
|  | 659b348a44 | ||
|  | 6990a8c942 | ||
|  | 98b4ee635d | ||
|  | 7d048d52f6 | ||
|  | 41fb54489f | ||
|  | 3be9ec308a | ||
|  | f120a17b1d | ||
|  | fc7054c150 | ||
|  | cde70f94db | ||
|  | 8f0f328dbf | ||
|  | 10e3bdcce3 | ||
|  | bc036c01cb | ||
|  | c14f565d18 | ||
|  | f56007d95f | ||
|  | 65599cfb58 | ||
|  | 39b2b95477 | ||
|  | e65561feae | ||
|  | 2a2170efc0 | ||
|  | adb5fb90b1 | ||
|  | ad9e16c198 | ||
|  | 96a20ae9d4 | ||
|  | 0cadf7ba66 | ||
|  | bb5ccf8869 | ||
|  | 57d19b3f1b | ||
|  | e45d947322 | ||
|  | b44cdfc143 | ||
|  | 385933819e | ||
|  | 58e3ba19a2 | ||
|  | 0f3ab63a24 | ||
|  | 2697eddcba | ||
|  | 90ba925a19 | ||
|  | b5d23f1591 | ||
|  | e6f0290d9f | ||
|  | 23a3de988f | ||
|  | c4fc6c2381 | ||
|  | 9bc24aea56 | ||
|  | 8392d2853e | ||
|  | 28708849a9 | ||
|  | 9f1538687a | ||
|  | 0ae26564ce | ||
|  | 9c146b8a6f | ||
|  | 2913ac8b4e | ||
|  | 6556fcc3fc | ||
|  | 1c6b3062bf | ||
|  | b00600c247 | ||
|  | 97d680c924 | ||
|  | 8f606cf0f6 | ||
|  | c05aa13dcf | ||
|  | 12389f2089 | ||
|  | b3cb194c03 | ||
|  | 1ea4c6d449 | ||
|  | e5526cb27e | ||
|  | 8a8a182679 | ||
|  | 2f19cff4df | ||
|  | 0bceef8c78 | ||
|  | 40eee88b06 | ||
|  | 0c79543cfe | ||
|  | 6ea66f6925 | ||
|  | 8891680304 | ||
|  | 1f80f8f371 | ||
|  | d2fefb2e80 | ||
|  | b3032f918e | ||
|  | bb37f26bbf | ||
|  | e805bfb103 | ||
|  | a1cbc61c34 | ||
|  | e3deef3baa | ||
|  | 4b81bb549d | ||
|  | c0274f4018 | ||
|  | 46ac061fb3 | ||
|  | 5e4a1476b3 | ||
|  | 3415f08149 | ||
|  | c384ad4074 | ||
|  | 8a9dbd13e7 | ||
|  | 1e2f3763cb | ||
|  | bc9b386f80 | ||
|  | b4940ed53c | ||
|  | 1e9221af45 | ||
|  | 200675b506 | ||
|  | 6424bd9e6d | ||
|  | 7ce425114e | ||
|  | b0e9ba5f4b | ||
|  | 7837f37e21 | ||
|  | 966bfcef27 | ||
|  | 70ebb39097 | ||
|  | 60d340b387 | ||
|  | 22812bc83c | ||
|  | 83c37777f1 | ||
|  | a200f50bbe | ||
|  | a2f563f84f | ||
|  | d5c94a08a7 | ||
|  | 9fc47d67df | ||
|  | c697497923 | ||
|  | b13837c2c0 | ||
|  | 5eb6300c77 | ||
|  | a1b86401a5 | ||
|  | 5dcb17df67 | ||
|  | 5b94a87589 | ||
|  | 3698ce35b1 | ||
|  | e6ce16ae13 | ||
|  | 7e8110ec50 | ||
|  | 482cef7121 | ||
|  | 3c3e95a5a8 | ||
|  | e0a4b67e11 | ||
|  | 56c7200837 | ||
|  | 0381e82b54 | ||
|  | 28b075f78d | ||
|  | 4f4c217659 | ||
|  | 55d9104463 | ||
|  | be2679a691 | ||
|  | 69281c1eab | ||
|  | ea249ebca7 | ||
|  | e60fe35e6b | ||
|  | a1945b9f12 | ||
|  | d41c8aed57 | ||
|  | fbf215ade2 | ||
|  | 5b679c060d | ||
|  | acb88b5339 | ||
|  | c3d7df946e | ||
|  | 1dea3b9fab | ||
|  | 3801cb524c | ||
|  | 001b2c264b | ||
|  | f1e5a95d89 | ||
|  | 8779301c8d | ||
|  | 2ac0e8f989 | ||
|  | f912e2c887 | ||
|  | 732528e1c0 | ||
|  | 90222d0232 | ||
|  | 85933f336c | ||
|  | dc60e49a4d | ||
|  | d1626c2433 | ||
|  | 2b3e80e233 | ||
|  | 0eb26e4582 | ||
|  | 79a9cb910a | ||
|  | 5b958643be | ||
|  | 6e17f8809d | ||
|  | 75ab0236a9 | ||
|  | 4928dded55 | ||
|  | 61325c32b0 | ||
|  | 4f2136c654 | ||
|  | 9489a09e01 | ||
|  | b55eb45e6a | ||
|  | 294097601d | ||
|  | 92afd60d92 | ||
|  | 6bb64bc0b7 | ||
|  | 16138ebca3 | ||
|  | bcf4cf83e4 | ||
|  | 5d3834485e | ||
|  | 4bd06a929d | ||
|  | 9f8d31c4a2 | ||
|  | e01d8e9702 | ||
|  | 212f7e0409 | ||
|  | 676492a634 | ||
|  | 39311f404e | ||
|  | 60b5c7dab1 | ||
|  | fe80296ff0 | ||
|  | e945819706 | ||
|  | caad1b4ff9 | ||
|  | 2286995abd | ||
|  | 3548ba3827 | ||
|  | de2c6ce36e | ||
|  | af1144cac0 | ||
|  | 4894259eca | ||
|  | ab3b542a18 | ||
|  | 262ff6e9d3 | ||
|  | 968c382706 | ||
|  | d99a0313a7 | ||
|  | ad2a90ccc6 | ||
|  | 64013278fb | ||
|  | 86a974c3c3 | ||
|  | f56361e29f | ||
|  | b53badf298 | ||
|  | 93bd371b57 | ||
|  | 3bb9c8e43e | ||
|  | 09c6b90d76 | ||
|  | 032a206a83 | ||
|  | 735d51276c | ||
|  | bc91078978 | ||
|  | 8179a2dc9c | ||
|  | ab98a1c5dc | ||
|  | d9f958852c | ||
|  | 27b0895f6d | ||
|  | fec4084b90 | ||
|  | 9a9d7c1c55 | ||
|  | 0f287ed3dd | ||
|  | cf048beade | ||
|  | 558c22a454 | ||
|  | 683f33139e | ||
|  | 810abed9ea | ||
|  | 9bd893bbc7 | ||
|  | abf79b3678 | ||
|  | 290d1d8c3f | ||
|  | f1ec47e131 | ||
|  | 0e36229da2 | ||
|  | 5d5d6e4d4a | ||
|  | 543f8e8cca | ||
|  | d5f5a46b33 | ||
|  | ac146fc759 | ||
|  | 5b5c981c13 | ||
|  | fbe2b85f22 | ||
|  | 377a39fcaf | ||
|  | 6674b9a66f | ||
|  | 73ac1ba150 | ||
|  | fa3bfb017b | ||
|  | c755772a23 | ||
|  | 441a1d7ee2 | ||
|  | f6318121f4 | ||
|  | 88943533dd | ||
|  | fba05d7ba1 | ||
|  | d302389b9f | ||
|  | 14ccfd53b5 | ||
|  | e0256ba49a | ||
|  | 22f922671e | ||
|  | 589f03e91a | ||
|  | 759241e905 | ||
|  | b68cb6026e | ||
|  | b1b18e183c | ||
|  | 64cdefc540 | ||
|  | 52aa8cabe3 | ||
|  | e420410f9a | ||
|  | 45f69c7d5f | ||
|  | 612b90ba52 | ||
|  | ae0ac24fdd | ||
|  | 4e51f802a0 | ||
|  | e4c3b136f5 | ||
|  | f1329d4511 | ||
|  | ee5f8f12bf | ||
|  | cb41445647 | ||
|  | 6d518948a9 | ||
|  | 45628f9813 | ||
|  | affe488e93 | ||
|  | c294dbb4c8 | ||
|  | a60e991ee7 | ||
|  | 3cfab15e8a | ||
|  | eb8af4be25 | ||
|  | 014546ad62 | ||
|  | e2240edafc | ||
|  | e4d6cfc013 | ||
|  | 79e3827207 | ||
|  | ba29d593b9 | ||
|  | b53f7f9993 | ||
|  | e6e871afbe | ||
|  | 45edc2ae3f | ||
|  | d54db5013b | ||
|  | 5426e85284 | ||
|  | 81631b1986 | ||
|  | df1b244fda | ||
|  | 004cda1b64 | ||
|  | 97c6592073 | ||
|  | 949b8c519b | ||
|  | e59624d6e9 | ||
|  | 74b228ee94 | ||
|  | 1565532bc7 | ||
|  | 21a17f291c | ||
|  | 919568a223 | ||
|  | ec81f7151d | ||
|  | 46eae0cdd8 | ||
|  | e5ecec8140 | ||
|  | 401f9e0eaf | ||
|  | 06769c9ccd | ||
|  | 009e7950bf | ||
|  | 66ad893ca4 | ||
|  | 15f4b08f94 | ||
|  | 9b4b94edc0 | ||
|  | 476099efc1 | ||
|  | cab4c903d0 | ||
|  | d9da96c8ad | ||
|  | d9ea736248 | ||
|  | b4dc68ba50 | ||
|  | 786f8576e3 | ||
|  | ec739277a1 | ||
|  | 8376fd198f | ||
|  | 39429d3905 | ||
|  | 4fb84eedfe | ||
|  | 1a64b3c812 | ||
|  | 66c590c89c | ||
|  | 821c266f1d | ||
|  | 4e63287d75 | ||
|  | 7f5ac28c78 | ||
|  | 52cd4a5893 | ||
|  | 04c5af2130 | ||
|  | 52893778f8 | ||
|  | 600e67b17a | ||
|  | 2da49b93bd | ||
|  | a65df0e598 | ||
|  | 54d4416ef8 | ||
|  | 42a7af1632 | ||
|  | cfbbf34d6a | ||
|  | 5b35bbdf1b | ||
|  | 0c46d48e40 | ||
|  | e78ad5f175 | ||
|  | 09c2296a9a | ||
|  | 55a3cf7ecd | ||
|  | 180705e9eb | ||
|  | f5cf560a3c | ||
|  | 1e11b5dd7c | ||
|  | f201c75a24 | ||
|  | 41219737ad | ||
|  | 35d1b6665c | ||
|  | 0543201db1 | ||
|  | 8e4da1d397 | ||
|  | 2977bfa721 | ||
|  | 5fa92bf619 | ||
|  | 3e37822415 | ||
|  | 4d65f59824 | ||
|  | cd5829fc42 | ||
|  | 86b056872d | ||
|  | b1007b02c0 | ||
|  | d3126d15cf | ||
|  | d61ed147ac | ||
|  | b1f3aa2920 | ||
|  | 8ad3bb1462 | ||
|  | b91a077d23 | ||
|  | 3df29c1667 | ||
|  | abf6c8eb4d | ||
|  | cffd634681 | ||
|  | e72e8cc71f | ||
|  | 8eaef39b33 | ||
|  | 1588334093 | ||
|  | 6f4fb574ec | ||
|  | 64cc7834a8 | ||
|  | 11e2edcf5f | ||
|  | f900ddb544 | ||
|  | 4f60a6ea02 | ||
|  | dc1bc980d0 | ||
|  | 3d3ae02e62 | ||
|  | a70a110f31 | ||
|  | 05d3869acf | ||
|  | 72489fb458 | ||
|  | fe8b1db933 | ||
|  | 8fdd90eb40 | ||
|  | 564a356f09 | ||
|  | 3927137203 | ||
|  | f826ad5c89 | ||
|  | 517ee7f6c3 | ||
|  | 99cc41356c | ||
|  | e76736cf55 | ||
|  | 2a7bbc7e46 | ||
|  | bda6449118 | ||
|  | e6166e4498 | ||
|  | 80a878ade5 | ||
|  | bbf2fcf17a | ||
|  | c1d266bd9a | ||
|  | 7a7f3f2f5b | ||
|  | 0371941707 | ||
|  | 6f449e65a4 | ||
|  | 5491f09bab | ||
|  | 6949ec443e | ||
|  | 47ca8f9c12 | ||
|  | ba303a615b | ||
|  | 350582bc7b | ||
|  | b9836e714a | ||
|  | aae30e6db5 | ||
|  | 86e46f17de | ||
|  | fbc263659b | ||
|  | 8c8a7cbba4 | ||
|  | f5e3cd0dbf | ||
|  | 24c1a0954b | ||
|  | f05cf23b89 | ||
|  | 90c883c201 | ||
|  | 2d0b95cd49 | ||
|  | e2bc7a277e | ||
|  | adbd3e478b | ||
|  | 7b0804c22f | ||
|  | 47dfe904ab | ||
|  | 7f5b44b423 | ||
|  | c16ca69070 | ||
|  | 394c628931 | ||
|  | 43695024af | ||
|  | 1678de7f51 | ||
|  | 063436c82b | ||
|  | 59585550a7 | ||
|  | 51e294c501 | ||
|  | 22ffec640d | ||
|  | 7ab3c4c091 | ||
|  | 19934a59b2 | ||
|  | f3645e3f4b | ||
|  | d818035d3a | ||
|  | 0cce8cfbaa | ||
|  | 3e132d71f5 | ||
|  | 2b3a4adff8 | ||
|  | de49d45568 | ||
|  | de5337b187 | ||
|  | f0e82e4473 | ||
|  | 5a00c29f8a | ||
|  | dd5d9aa6bc | ||
|  | 40f03c4c2c | ||
|  | 1aaf8d589f | ||
|  | 1b87c6ade7 | ||
|  | d52e9c7704 | ||
|  | 9c7425eee4 | ||
|  | 7cd8b4410e | ||
|  | c63e78714a | ||
|  | 2b34836c61 | ||
|  | 32d1d7b23f | ||
|  | e7773faa8d | ||
|  | b7c2a2b709 | ||
|  | 67ef389a69 | ||
|  | 7c1903a0c3 | ||
|  | c8563cac0a | ||
|  | 42c4a7757d | ||
|  | 8b007b358e | ||
|  | 5cd2cfc203 | ||
|  | a7ca42cb22 | ||
|  | f562bcedef | ||
|  | a8dc5260b7 | ||
|  | d33d0b01bf | ||
|  | 4a5195c38a | ||
|  | 0864378250 | ||
|  | 855e4aac41 | ||
|  | 5f8a3896dc | ||
|  | 903bfcaf4b | ||
|  | fcf46a9a42 | ||
|  | 1d1db98a2e | ||
|  | 51c8e01575 | ||
|  | b87c774102 | ||
|  | 6aa05bdc37 | ||
|  | 4abee1da76 | ||
|  | 2106e8f031 | ||
|  | 4befd355b3 | ||
|  | a544f403a2 | ||
|  | 8f1afa1766 | ||
|  | c0789ae1b4 | ||
|  | 9934a167a2 | ||
|  | 798ffad9a9 | ||
|  | fb3b7f2274 | ||
|  | 23dd62ec54 | ||
|  | a1affa1dc3 | ||
|  | 23633cf632 | ||
|  | 472bd55757 | ||
|  | 2de4f65474 | ||
|  | 38befc5ded | ||
|  | 5f9d855d3e | ||
|  | 3c5d941945 | ||
|  | 2f54dbd28c | ||
|  | b2b6c18db3 | ||
|  | 33e7126ba5 | ||
|  | 2ab98aa919 | ||
|  | 9ba875e502 | ||
|  | 2dcdb807f8 | ||
|  | 56fe3c6176 | ||
|  | 321b26f3d4 | ||
|  | ad37ab272a | ||
|  | d5feddb0a0 | ||
|  | 88ae26178c | ||
|  | e06357084e | ||
|  | 2e52c46165 | ||
|  | a82cf6080e | ||
|  | 78f321b32c | ||
|  | 3113200309 | ||
|  | 4a854b2927 | ||
|  | a5e61545e4 | ||
|  | 17a259e894 | ||
|  | f5fb224254 | ||
|  | fe07d17374 | ||
|  | 8d983d6f2d | ||
|  | 2c028990b4 | ||
|  | 35af86cef2 | ||
|  | 659f47f76a | ||
|  | b489acb578 | ||
|  | e34342c1f3 | ||
|  | 1f6952ba81 | ||
|  | d2f48d07bb | ||
|  | e9306bead5 | ||
|  | a3bdff883b | ||
|  | ddedf42d21 | ||
|  | b3e684d1fe | ||
|  | b3a13b17cb | ||
|  | 90b4fce199 | ||
|  | 2d3164a59f | ||
|  | 37ee12b2eb | ||
|  | d8d4a1d694 | ||
|  | 0b18937cbe | ||
|  | 264091a239 | ||
|  | d324fd94df | ||
|  | 15352cd86e | ||
|  | 69ca87abad | ||
|  | e0c8e7c740 | ||
|  | 8a9f96b21c | ||
|  | bfb05107e3 | ||
|  | 1e699db631 | ||
|  | f3953f9a15 | ||
|  | 7c7f889b1e | ||
|  | f437c92b00 | ||
|  | 44dd5c38e2 | ||
|  | e0132ef4cb | ||
|  | 94cb2db723 | ||
|  | 52cf11338e | ||
|  | c4cce91dce | ||
|  | 23aa1c6524 | ||
|  | 9de129d5b2 | ||
|  | 9d4cb8e97a | ||
|  | c1589415f0 | ||
|  | 389cbc3686 | ||
|  | 2508b4000b | ||
|  | e5164acc9c | ||
|  | 71ee58b6bb | ||
|  | 3512a6ad0b | ||
|  | b02de599a0 | ||
|  | 38c6e8faf6 | ||
|  | 431ca070a4 | ||
|  | ed2630dce5 | ||
|  | 5a2c9c9cee | ||
|  | a7184430f1 | ||
|  | 2e83fee74c | ||
|  | bbe29582cb | ||
|  | 76470d9608 | ||
|  | 715c4ca4cd | ||
|  | c097423d77 | ||
|  | 54637fa44d | ||
|  | c192e88bcd | ||
|  | 19a12b28bc | ||
|  | d55a7f18b0 | ||
|  | 4008a5fbf9 | ||
|  | e260f729da | ||
|  | 17cffe2bf9 | ||
|  | d1b068a68a | ||
|  | a5053f6ada | ||
|  | 261a3e7e78 | ||
|  | 36e28d4b4b | ||
|  | cbc562a636 | ||
|  | 51c4e1ea4b | ||
|  | c8f03c38fe | ||
|  | 4107d4d24d | ||
|  | f0c79d95f5 | ||
|  | d13b495217 | ||
|  | 549e1dfb0d | ||
|  | e260ecef0b | ||
|  | b16b4d92a7 | ||
|  | c2584edbdb | ||
|  | aa00196b6f | ||
|  | 75e3996d36 | ||
|  | d50f13b90d | ||
|  | 652e9c00c5 | ||
|  | fdcf749779 | ||
|  | ed38f47f23 | ||
|  | 3b0585be3b | ||
|  | ebe1a8080c | ||
|  | 593bb6470b | ||
|  | 6ce45042ef | ||
|  | f615e84381 | ||
|  | bfaf1a4ecc | ||
|  | bc1a30f542 | ||
|  | 28e0d5dd64 | ||
|  | ffdd12841e | ||
|  | 4b660a89d9 | ||
|  | 48386caec5 | ||
|  | 996360df6b | ||
|  | fe260a26ed | ||
|  | 457bc4fb63 | ||
|  | eeb7ce60ae | ||
|  | e52586db1c | ||
|  | 6cb9642200 | ||
|  | 7ebd46ee53 | ||
|  | d575dfe440 | ||
|  | 074c1880ff | ||
|  | b53c1011fc | ||
|  | 11f35d31d9 | ||
|  | 36d07a5cea | ||
|  | 12910a5a29 | ||
|  | eb93c134a7 | ||
|  | 493ad74331 | ||
|  | a563816d3a | ||
|  | 43526902ae | ||
|  | b6ec0f9b92 | ||
|  | 4e7f1a3a9d | ||
|  | 50e879ef56 | ||
|  | 06468b9049 | ||
|  | 2bdbceca91 | ||
|  | d34d85efdd | ||
|  | 7e3278ae8f | ||
|  | bca7c09e6c | ||
|  | 2e163858fc | ||
|  | 0ad2a4c72f | ||
|  | b69ca133af | ||
|  | d4f0f090c0 | ||
|  | e56f421490 | ||
|  | c9b93bf65a | ||
|  | 9b8ce15725 | ||
|  | 014e7daa36 | ||
|  | 306e3b86f1 | ||
|  | ce7cf5f46b | ||
|  | 3c3b5e0dbf | ||
|  | 0fc136fcc7 | ||
|  | 80328439be | ||
|  | 3c649de483 | ||
|  | 184ca578a0 | ||
|  | 3643acadac | ||
|  | 1c78aa19ff | ||
|  | a64fec0722 | ||
|  | 962811198f | ||
|  | 378c3b1641 | ||
|  | 34c937510d | ||
|  | e924e9cfb2 | ||
|  | 8f0fa65379 | ||
|  | 00268c1b82 | ||
|  | 7ab37c0ffc | ||
|  | 4cae37c340 | ||
|  | 63f8ad01b2 | ||
|  | 1a6159aca5 | ||
|  | 60e9c014a2 | ||
|  | 8f3295456d | ||
|  | 78df2efac2 | ||
|  | 546357eaeb | ||
|  | 50552f3fd5 | ||
|  | 7d62ac4b34 | ||
|  | beb14c3fa7 | ||
|  | a15d3d8dcc | ||
|  | 9c7755c862 | ||
|  | 866553e76f | ||
|  | f8f2be527f | ||
|  | 88880e1f89 | ||
|  | 3cce4419c2 | ||
|  | bc59859a59 | ||
|  | ecf06d3a49 | ||
|  | d48af1520d | ||
|  | aa9797fa3c | ||
|  | 44a82780b9 | ||
|  | c76681596e | ||
|  | 3ce8520c5e | ||
|  | 01f5823ee4 | ||
|  | c7ec3c65f4 | ||
|  | d01b8d03db | ||
|  | 41ff900c99 | ||
|  | 9ca07f4298 | ||
|  | 0e93522190 | ||
|  | ebd1d49150 | ||
|  | 057462c4e6 | ||
|  | b5e36cb96b | ||
|  | f58ca71942 | ||
|  | 262a39dfd0 | ||
|  | d531d56dbb | ||
|  | 8b78a832fa | ||
|  | 8c19b52bda | ||
|  | a7237281ea | ||
|  | 0b6ee2252c | ||
|  | a9ffbb0803 | ||
|  | 224457fb0f | ||
|  | cacbf14d8e | ||
|  | b00dc7153a | ||
|  | 9dbad2f74d | ||
|  | 97617cfc76 | ||
|  | 735cac19f2 | ||
|  | 3755951091 | ||
|  | 60af6fb0a2 | ||
|  | 333cf73ceb | ||
|  | bc653452a7 | ||
|  | ca92b9a5f0 | ||
|  | afe102c0fe | ||
|  | fa7fa300e3 | ||
|  | 3c2b019578 | ||
|  | 87003ba5b1 | ||
|  | bf7d3d2208 | ||
|  | 4e553333d9 | ||
|  | 954df8f3d7 | ||
|  | 078573dc2c | ||
|  | c4655582e6 | ||
|  | 360f97c31d | ||
|  | f20300cc8b | ||
|  | f687bd63b8 | ||
|  | b68340f6d9 | ||
|  | c5eb266a80 | ||
|  | 04f3cea84a | ||
|  | c1fe5092c3 | ||
|  | 5257248ed9 | ||
|  | 780010a268 | ||
|  | 8571d54f61 | ||
|  | 13fed1e445 | ||
|  | 2179ff624c | ||
|  | 8b3434061e | ||
|  | 68a6a348b5 | ||
|  | d8659175cd | ||
|  | 1431ddad9c | ||
|  | 5f860775c8 | ||
|  | 65f5ed533f | ||
|  | c4276aad11 | ||
|  | d4ae0dedf2 | ||
|  | 312a15d24e | ||
|  | bc1024812a | ||
|  | 451be927a8 | ||
|  | 4839e5d913 | ||
|  | 874d697f4c | ||
|  | f80cbe8c33 | ||
|  | 154a7af5ee | ||
|  | cea69ab9d0 | ||
|  | 6b3f81e647 | ||
|  | fbee662499 | ||
|  | eedf87f891 | ||
|  | 89cb3a410a | ||
|  | ae1ec1b418 | ||
|  | c357c91b7d | ||
|  | b3f073c48c | ||
|  | cd8ffd8725 | ||
|  | bbe4a85be1 | ||
|  | 7e6f58c0a9 | ||
|  | 275654210d | ||
|  | f649252de9 | ||
|  | d3ce80e544 | ||
|  | ea956b4f6c | ||
|  | ada4c61860 | ||
|  | 9bcaa94756 | ||
|  | 49a81e190e | ||
|  | 5303eca8fa | ||
|  | 1b37183e74 | ||
|  | 09f17bf72d | ||
|  | 449ffc7b05 | ||
|  | bea9cf6725 | ||
|  | a0c7ead88f | ||
|  | 3eb97ffa25 | ||
|  | 48d651f492 | ||
|  | 0d272a6964 | ||
|  | 578c4098e6 | ||
|  | c34cb6adcf | ||
|  | cb5d05fd34 | ||
|  | 5899d9b442 | ||
|  | 40026b0762 | ||
|  | 83b4f8366a | ||
|  | 8e50c4e4bb | ||
|  | 2b129732b0 | ||
|  | 8cf86745c2 | ||
|  | 5ee39f1a1d | ||
|  | 8c998ebbed | ||
|  | e2eb9b24b7 | ||
|  | 374e3502fe | ||
|  | 1ad6e72ade | ||
|  | d7eaafe9c1 | ||
|  | 2400150734 | ||
|  | 8ad2a270f4 | ||
|  | 73a006403f | ||
|  | a3513577f0 | ||
|  | 29ad12df51 | ||
|  | e0dd25f92b | ||
|  | 81c155b465 | ||
|  | ae11cc6731 | ||
|  | b0b0c853c7 | ||
|  | 8701c4f50c | ||
|  | 627d5adc63 | ||
|  | 7a5a31888a | ||
|  | 3d64743851 | ||
|  | 16d704877d | ||
|  | 3e320285a1 | ||
|  | 3215d89e97 | ||
|  | b7983d4fe2 | ||
|  | 6120f4c507 | ||
|  | ac24748b47 | ||
|  | 4c449886f6 | ||
|  | cd3475a8cb | ||
|  | 03c5c5fbe7 | ||
|  | 9d3faa4753 | ||
|  | 20399b50d6 | ||
|  | 93c1312901 | ||
|  | 4bde7fc926 | ||
|  | 68086fdde4 | ||
|  | 005ad96068 | ||
|  | 6c1beb94dc | ||
|  | fa0ec772d5 | ||
|  | 661e73d9a6 | ||
|  | db85b2ddc7 | ||
|  | 4f732b1989 | ||
|  | 78b8276111 | ||
|  | 6ef6b6af40 | ||
|  | f45bbeb497 | ||
|  | 4eb71369ed | ||
|  | bc11c3a1d7 | ||
|  | dd8ac54678 | ||
|  | 15d7886699 | ||
|  | 68c7b86df1 | ||
|  | 6c8454e4e2 | ||
|  | a249779692 | ||
|  | 876b6416ab | ||
|  | 1e5d79dce1 | ||
|  | bd8eec0a1e | ||
|  | e7075c4366 | ||
|  | 532834cbc2 | ||
|  | d5857e6d48 | ||
|  | b004ea2d7f | ||
|  | 205ca4f8a7 | ||
|  | 4a76f5c764 | ||
|  | a32e8441d0 | ||
|  | 4d6089c042 | ||
|  | 7929929979 | ||
|  | 9ba50046cf | ||
|  | aa3bdb1911 | ||
|  | 5ce8c9ae77 | ||
|  | 9d8d6b1d18 | ||
|  | 52b8978a47 | ||
|  | 442fd05339 | ||
|  | 4c952f0af4 | ||
|  | cf90b03ce4 | ||
|  | d4de2a7aa4 | ||
|  | e37b173f13 | ||
|  | b5d88e683f | ||
|  | 23dd4773d4 | ||
|  | b7af7c9c43 | ||
|  | 9d3955daf2 | ||
|  | 063083a203 | ||
|  | 46886164dd | ||
|  | ea04c0775c | ||
|  | d29aa4764e | ||
|  | 203d1d8371 | ||
|  | 2eb4099563 | ||
|  | 7cd66377ef | ||
|  | 1f9d50fa3f | ||
|  | be29e5ab62 | ||
|  | 24d8818933 | ||
|  | 803380c203 | ||
|  | 1569059b2b | ||
|  | 8fb6bd930b | ||
|  | c7cc4b7ac2 | ||
|  | 201d0e940b | ||
|  | 3fcd56034a | ||
|  | 51d222469c | ||
|  | 742d1e9424 | ||
|  | a04f401227 | ||
|  | 62699dc3fd | ||
|  | 01645a7eae | ||
|  | b17939f74e | ||
|  | aa60387ecc | ||
|  | 4b801e21e3 | ||
|  | c198ca0285 | ||
|  | a312fc8eb9 | ||
|  | 10b62fb0e8 | ||
|  | 2c12325d63 | ||
|  | 2d8b9935a1 | ||
|  | 647d948562 | ||
|  | 73d1626ddc | ||
|  | b7445913cc | ||
|  | 6f7ca25c9b | ||
|  | 4487c42de2 | ||
|  | bfbad87685 | ||
|  | 65f0ca65f1 | ||
|  | d0720d5638 | ||
|  | 5d7fd71373 | ||
|  | efe3e72ed0 | ||
|  | 85f56aef97 | ||
|  | 5ac0fdd924 | ||
|  | b33c7a4597 | ||
|  | 788b9bfdc7 | ||
|  | 41cc3b216d | ||
|  | dcb7878842 | ||
|  | b5e83471bc | ||
|  | bfdc05ec71 | ||
|  | 1d7ecbe9a0 | ||
|  | 9e30a829d5 | ||
|  | 698dfbf953 | ||
|  | 83fbb1ec11 | ||
|  | 19d0f2b57c | ||
|  | 05d40b3142 | ||
|  | d94fc9ce62 | ||
|  | ba9550f473 | ||
|  | 28e1e7fd07 | ||
|  | 904e38837e | ||
|  | 697c5de267 | ||
|  | bfa9c7bcfb | ||
|  | 2f81a05ce5 | ||
|  | 7b994976e3 | ||
|  | 662d1021e6 | ||
|  | 2db34bd266 | ||
|  | f3491d93a0 | ||
|  | 337abee8f8 | ||
|  | 34573cf6a5 | ||
|  | 491ef790c2 | ||
|  | 2e9ae681c5 | ||
|  | a02f7ab0cb | ||
|  | e0b190c111 | ||
|  | 56fa3ac1b0 | ||
|  | 5bcbeca8e7 | ||
|  | adc1729212 | ||
|  | fd7ae0cdf4 | ||
|  | fdef9679b6 | ||
|  | dcecda51d8 | ||
|  | 687603a144 | ||
|  | acb04c003e | ||
|  | 86b10089aa | ||
|  | 7b030379ec | ||
|  | 5e8c230d1f | ||
|  | 8c2890cf1d | ||
|  | 8e9da71c32 | ||
|  | 13deb51d3e | ||
|  | 2c9ffffdca | ||
|  | 13a9bce647 | ||
|  | dbb3cfe05e | ||
|  | 674baa8143 | ||
|  | db482f3e1c | ||
|  | 6a5a0222d7 | ||
|  | 4512267bf1 | ||
|  | 54555a6fab | ||
|  | ae2353caf8 | ||
|  | 4eae19ed75 | ||
|  | e6ec837203 | ||
|  | b37f7c4b7b | ||
|  | 4b8340327c | ||
|  | 92e4442d4a | ||
|  | 2517f9adf2 | ||
|  | 9bad64ff72 | ||
|  | d1b147e2bb | ||
|  | 1b7730c76a | ||
|  | 28801f7470 | ||
|  | f4c43c11c9 | ||
|  | fde4a8e1b5 | ||
|  | abb193533c | ||
|  | 775fac97d3 | ||
|  | 3963c01760 | ||
|  | 1e01a63685 | ||
|  | 235ca704b1 | ||
|  | 5685ba7918 | ||
|  | f0d1c085b9 | ||
|  | 45490081c7 | ||
|  | a3503d13e5 | ||
|  | 3ed4d07d3a | ||
|  | 06e0023c2c | ||
|  | b22e0a3ecb | ||
|  | 0802006ea7 | ||
|  | 29a21d1627 | ||
|  | a0074aa07e | ||
|  | 4e8859d851 | ||
|  | 562ae607d2 | ||
|  | 2426656b07 | ||
|  | 898d3c655d | ||
|  | 855e554051 | ||
|  | 4aac2c543b | ||
|  | 78024e7be6 | ||
|  | 18f0009a41 | ||
|  | 1cf64de2bf | ||
|  | b1d6be8ec6 | ||
|  | 137a25906d | ||
|  | 2b298cbb32 | ||
|  | 5361b5de37 | ||
|  | f1fee292e4 | ||
|  | 9c9b1f5bc8 | ||
|  | 7e64d04db1 | ||
|  | 2355f677fb | ||
|  | e42bb91382 | ||
|  | 28aa06675f | ||
|  | 6e86d0bb03 | ||
|  | 4342431e39 | ||
|  | 7452298131 | ||
|  | e4be66b1ac | ||
|  | f829547a13 | ||
|  | ea64fe3b51 | ||
|  | f293d0b951 | ||
|  | 1967fd2429 | ||
|  | 0fec0340c2 | ||
|  | bed67320b1 | ||
|  | 8544e24770 | ||
|  | 727b7b7e8c | ||
|  | bd39789144 | ||
|  | eb10fc962b | ||
|  | 3318c41356 | ||
|  | dc2c0b1d51 | ||
|  | 1de8da23f5 | ||
|  | 340fa684af | ||
|  | 34f06fa400 | ||
|  | 5b5337e4af | ||
|  | d01de820d7 | ||
|  | 5aeea69c01 | ||
|  | 8f6c0b24d8 | ||
|  | b8eddf1bdc | ||
|  | 1469dc216a | ||
|  | 3306ae2f42 | ||
|  | a89db8e69c | ||
|  | 8c6f06eb34 | ||
|  | fe3ed2b871 | ||
|  | 71cb3fc201 | ||
|  | f9554c7d27 | ||
|  | 384f2fc38b | ||
|  | cd50107ae1 | ||
|  | 94466645ee | ||
|  | 1acb442f60 | ||
|  | cff0a562fd | ||
|  | 299db29482 | ||
|  | cc5045d8ca | ||
|  | 940c32c5dd | ||
|  | 14ad41a065 | ||
|  | 7eaf1f294d | ||
|  | eb7692743f | ||
|  | 7aa470c8d0 | ||
|  | 4237ca85f5 | ||
|  | 99cdfa1e71 | ||
|  | 39f92f3cfd | ||
|  | 9cc29191d4 | ||
|  | de33332491 | ||
|  | f9ddafdc21 | ||
|  | fdefd5eff9 | ||
|  | e9e5dbb628 | ||
|  | 0e57141bb5 | ||
|  | 842a3664f0 | ||
|  | 6cf89391b6 | ||
|  | ca5fd21509 | ||
|  | d14471e44d | ||
|  | 5197fd72c4 | ||
|  | c17ac96509 | ||
|  | 4acb30c464 | ||
|  | d61f611adc | ||
|  | b19719801b | ||
|  | 83a2bc8ec4 | ||
|  | aab6f07d14 | ||
|  | db8748cefd | ||
|  | 23b3f55bfb | ||
|  | e6573a9bed | ||
|  | d6a19426c7 | ||
|  | 9426d45cde | ||
|  | 48d0cd3564 | ||
|  | 89f61acf2c | ||
|  | 985d87b5eb | ||
|  | 0be2dfefdb | ||
|  | 89f30d2df7 | ||
|  | 0b648ce87b | ||
|  | 0c897ecefd | ||
|  | f2a6d937a6 | ||
|  | 76f4498303 | ||
|  | 5451f79f55 | ||
|  | 4e69ed9c98 | ||
|  | 75f55c758c | ||
|  | f9d1b67e86 | ||
|  | 04ecf25522 | ||
|  | 52b51b70eb | ||
|  | 3fdc1390fe | ||
|  | f309bd12c7 | ||
|  | d388f94c7f | ||
|  | 0f878a226d | ||
|  | a38f899d7e | ||
|  | 6c09d7b60c | ||
|  | 8cb8f65010 | ||
|  | 49437d9a07 | ||
|  | 69962eae7c | ||
|  | c440f39874 | ||
|  | 40090be220 | ||
|  | 281a92bf74 | ||
|  | bbacb7fff0 | ||
|  | cccdc3eea0 | ||
|  | aa9c970f97 | ||
|  | 4f81adb3c9 | ||
|  | b8f75d74ae | ||
|  | befffd65bf | ||
|  | 610cd1a531 | ||
|  | 08d06030dc | ||
|  | 083687d0fd | ||
|  | f874581701 | ||
|  | e66d76ac5a | ||
|  | 5d7ad8ae75 | ||
|  | 99ab428344 | ||
|  | eaef92b02f | ||
|  | 4982eabe07 | ||
|  | c66ce519f4 | ||
|  | e74208778d | ||
|  | 67a0635e75 | ||
|  | def0511361 | ||
|  | 29b8138482 | ||
|  | c6ee487cfc | ||
|  | 1a6df48bd0 | ||
|  | 6cdf300933 | ||
|  | 5365974d6c | ||
|  | f1acefd241 | ||
|  | 079fec6c5a | ||
|  | 14258c93de | ||
|  | 03315d77f1 | ||
|  | 34843e7d6c | ||
|  | 4efa67c4ec | ||
|  | 2419c1c540 | ||
|  | 34055f40ac | ||
|  | 276d32973f | ||
|  | f3c51a049d | ||
|  | 21573cd4f0 | ||
|  | f25325f4bb | ||
|  | 5b12edfb34 | ||
|  | 4697026132 | ||
|  | 6c39b8f4f0 | ||
|  | 4a9af35527 | ||
|  | 881056af0b | ||
|  | e5df490d5e | ||
|  | 7c0d6057c5 | ||
|  | 3e5a54a791 | ||
|  | dbfd6e0d12 | ||
|  | f607a0a0a6 | ||
|  | b15ada28ed | ||
|  | 6610f9bdbc | ||
|  | 5f87626377 | ||
|  | 54834a1761 | ||
|  | adf7081163 | ||
|  | a50b7c55d3 | ||
|  | f4f171e04d | ||
|  | d5ea20a6eb | ||
|  | 5584f2ae46 | ||
|  | b79d8b1ff0 | ||
|  | 1c33c0027f | ||
|  | aef0a98840 | ||
|  | 9d23a04c0e | ||
|  | 453bab220b | ||
|  | 448f8c4240 | ||
|  | 5a414c6ad1 | ||
|  | 65a942f01f | ||
|  | 6df32fed62 | ||
|  | 1199b48cd7 | ||
|  | c493f56e1b | ||
|  | 2e65b8ce5f | ||
|  | 42a6d954d3 | ||
|  | 8f73b4c3ae | ||
|  | adcd06fccb | ||
|  | c40380f72a | ||
|  | 8e44e884a2 | ||
|  | e2368be912 | ||
|  | 7986fd4db7 | ||
|  | 6107f4a02a | ||
|  | 2ce63814e9 | ||
|  | 8ba508f8f7 | ||
|  | 2100490424 | ||
|  | 7e7639e39a | ||
|  | 3555d0ecd5 | ||
|  | ecb9a01cfa | ||
|  | ca352ebfba | ||
|  | 29c73eb67b | ||
|  | 2a598ff24d | ||
|  | f6d5837e5e | ||
|  | dac8cee72c | ||
|  | e01a2f8324 | ||
|  | a092ccb82b | ||
|  | e894d07b92 | ||
|  | befef6eb00 | ||
|  | 162224979d | ||
|  | a90f6e2dda | ||
|  | e449bfd741 | ||
|  | 8ecc1eb99d | ||
|  | 1fb910411e | ||
|  | 3141b86d01 | ||
|  | f8ff64c87e | ||
|  | c71b834aad | ||
|  | a78e7d0287 | ||
|  | 09cf0fe6b9 | ||
|  | 13713bc147 | ||
|  | 9c17cf4edf | ||
|  | 938b25b986 | ||
|  | 040b76f1e6 | ||
|  | 66226207ce | ||
|  | 999b4168c1 | ||
|  | 9bfc452487 | ||
|  | df675ed9fb | ||
|  | 4a13ae4c95 | ||
|  | 5287c71d68 | ||
|  | 827f1a3d30 | ||
|  | f6d95e19c4 | ||
|  | 3eb93f161f | ||
|  | 801eff0c52 | ||
|  | c1993e76c2 | ||
|  | c23f56b9cb | ||
|  | 44e17e2aa9 | ||
|  | 84758667c1 | ||
|  | 8c71113cd6 | ||
|  | 79ba99811c | ||
|  | 55a664d6fd | ||
|  | b4affd607d | ||
|  | c7007c98d7 | ||
|  | fa684a97da | ||
|  | cad03afc54 | ||
|  | fe6d782751 | ||
|  | dfe517cfbe | ||
|  | 46ab95f24c | ||
|  | 9a57ea4c4a | ||
|  | 5fc98ffa69 | ||
|  | 814eb397e1 | ||
|  | 77f030956c | ||
|  | ab7ad3451d | ||
|  | 1107f82824 | ||
|  | 2bc2378033 | ||
|  | 676e214f34 | ||
|  | 7df1ccbf91 | ||
|  | 82d3ee5454 | ||
|  | fcb6fb00e0 | ||
|  | 4e09e6ca10 | ||
|  | af6dd44048 | ||
|  | d30ec9fd1e | ||
|  | 16ee54ad23 | ||
|  | 627409ec38 | ||
|  | 4ead572462 | ||
|  | 42783a54db | ||
|  | 84763527c5 | ||
|  | 1744c1c2ba | ||
|  | 7ef5fbdbe6 | ||
|  | b1482c52b7 | ||
|  | 7b0d61b96d | ||
|  | 951b974c4d | ||
|  | 975b3c3428 | ||
|  | f0420012e6 | ||
|  | 30e5413e2b | ||
|  | 5077a1bb83 | ||
|  | a8ed16de33 | ||
|  | ee0a4914d5 | ||
|  | 8b70a0d0b7 | ||
|  | 8e7c6b60fb | ||
|  | fbb0bb63e7 | ||
|  | 46dc1b6e99 | ||
|  | 82b34e06f2 | ||
|  | bc178df8f0 | ||
|  | d5a3de5a97 | ||
|  | b8774d7aac | ||
|  | 891246562f | ||
|  | e53a955115 | ||
|  | 1ec6812246 | ||
|  | e896691b0f | ||
|  | fbe92a13c0 | ||
|  | 94a434e9e7 | ||
|  | e829c626da | ||
|  | 837adeea7f | ||
|  | 65d6350d36 | ||
|  | ba99186951 | ||
|  | b3975f5098 | ||
|  | b90f909289 | ||
|  | d098e4def6 | ||
|  | 835b0d9f62 | ||
|  | 9fea2798e3 | ||
|  | 394cae5d21 | ||
|  | 7996aae5e9 | ||
|  | 9788b9d7a9 | ||
|  | 6f5e1c3d73 | ||
|  | d4421b12ba | ||
|  | 099b03f038 | ||
|  | f84d2eeec9 | ||
|  | f02531802c | ||
|  | 375cb5c31d | ||
|  | 8f2ba4ec3c | ||
|  | 9935d1183a | ||
|  | aff8e77bec | ||
|  | c9fd743c65 | ||
|  | 7a4fa925fc | ||
|  | ff442c1e28 | ||
|  | 5cedaa972a | ||
|  | 2c8f647e0c | ||
|  | 3be5edae0e | ||
|  | 1078f24d5a | ||
|  | c02cc5321a | ||
|  | e60a7ff1d0 | ||
|  | 91de7311d7 | ||
|  | e357c9fc0c | ||
|  | ec4daa5936 | ||
|  | 2743fb9771 | ||
|  | 88c4802bdc | ||
|  | a47e422715 | ||
|  | 3a9ab631e5 | ||
|  | 9ca5118a68 | ||
|  | d6053080f8 | ||
|  | b1f8076da0 | ||
|  | abc760c8e4 | ||
|  | 0331a34d58 | ||
|  | 98af0ba143 | ||
|  | 157810ea3d | ||
|  | 448e4251f8 | ||
|  | 81ce20d616 | ||
|  | 3e9ab41e76 | ||
|  | a3c8fbc6b6 | ||
|  | e9dc6880af | ||
|  | 25fb2c4fb6 | ||
|  | 97d28ae4d7 | ||
|  | b5bad15dae | ||
|  | 3098ef4a6e | ||
|  | e354b1210e | ||
|  | 895b6ff719 | ||
|  | 0a22655ff3 | ||
|  | 8def378b5e | ||
|  | 7ab8b44b6c | ||
|  | 335fe09d70 | ||
|  | 523a7ed7d3 | ||
|  | f69e8e3606 | ||
|  | 3516797b49 | ||
|  | 1683e94f0c | ||
|  | 1d249195a4 | ||
|  | 2f7ee08288 | ||
|  | e0772fb301 | ||
|  | 78bdbce2fd | ||
|  | 5a5fed28fa | ||
|  | 5818b6efb8 | ||
|  | 53a66492e8 | ||
|  | b17ddc26c0 | ||
|  | b7e19d2fe3 | ||
|  | d8130a99b4 | ||
|  | 8c654aeebe | ||
|  | bad318d451 | ||
|  | 11d2997e44 | ||
|  | 2d75d2e76e | ||
|  | 6074f58641 | ||
|  | 48de09c279 | ||
|  | 032c2cb462 | ||
|  | 2008367883 | ||
|  | 165d88cfd8 | ||
|  | 0c0e1fbbeb | ||
|  | 3559e20dab | ||
|  | e400f6eab9 | ||
|  | cffffe0c2e | ||
|  | 70fcdb495a | ||
|  | c1b2049df9 | ||
|  | f6cabc78c0 | ||
|  | b8526452b5 | ||
|  | a1cefb3e17 | ||
|  | def0f38f3d | ||
|  | 58a8b00086 | ||
|  | 50a27398b0 | ||
|  | eab7cba1f3 | ||
|  | 83774ba6ae | ||
|  | ab700b4ea3 | ||
|  | bf7936d494 | ||
|  | 14f627329d | ||
|  | 829c996611 | ||
|  | dff2e8ecb4 | ||
|  | 7c79b1c7c5 | ||
|  | a390fac356 | ||
|  | 9a43e67347 | ||
|  | b0d08c572a | ||
|  | ee4eb0aa6f | ||
|  | 07e27cac02 | ||
|  | cdc905cc16 | ||
|  | 88b0c82a0d | ||
|  | 01d3349587 | ||
|  | cf7f096db7 | ||
|  | 21ed352ac5 | ||
|  | f8a4f79277 | ||
|  | 16d385ac6a | ||
|  | 3dc1945b44 | ||
|  | 3c7db9e986 | ||
|  | 44e1f095d1 | ||
|  | 90c39b8371 | ||
|  | 17b7944ac2 | ||
|  | bbf486f890 | ||
|  | 20faa956a8 | ||
|  | 74a4e04185 | ||
|  | b102455b57 | ||
|  | c2235a0baa | ||
|  | c36d2b02a3 | ||
|  | 4eb8d86346 | ||
|  | 1b33fbf98b | ||
|  | 3f74391b87 | ||
|  | 93c954dae1 | ||
|  | f736563a7a | ||
|  | 0350c4f0f6 | ||
|  | 0c0caf0272 | ||
|  | 9abd966a80 | ||
|  | a1dbd7156c | ||
|  | b74e5b870c | ||
|  | bcb021296f | ||
|  | dcf907f36d | ||
|  | 972b11e39e | ||
|  | 10fffe842b | ||
|  | 963cf98df1 | ||
|  | 0f64ddf2fb | ||
|  | 3fa82818b9 | ||
|  | c48ba4464c | ||
|  | 2d1118a26f | ||
|  | 53560b8e0b | ||
|  | 3f647cdf32 | ||
|  | 9a0dc6d522 | ||
|  | c819525e81 | ||
|  | 4024ad5eb2 | ||
|  | 2c0df9552f | ||
|  | 9359586fde | ||
|  | 68069c70e1 | ||
|  | 6a00ceeb66 | ||
|  | 8143f55488 | ||
|  | 03e03fb7a1 | ||
|  | b13b8c1882 | ||
|  | 02a2afb64f | ||
|  | ae8e907d72 | ||
|  | f042834068 | ||
|  | 63130374b9 | ||
|  | ac01d56747 | ||
|  | 6f751afae4 | ||
|  | 8fd85fb6e6 | ||
|  | 1dbfe1e856 | ||
|  | d3fd4c0381 | ||
|  | 0e20e05795 | ||
|  | 3bb0dc03af | ||
|  | 4257485ff2 | ||
|  | f69b7a58f2 | ||
|  | fd4fe42013 | ||
|  | 930820b738 | ||
|  | 06cc081ca2 | ||
|  | ee9bf16d1a | ||
|  | f08e65fd04 | ||
|  | 877de45d6e | ||
|  | 5a4813d336 | ||
|  | 6dc818deb1 | ||
|  | 4b2bf06873 | ||
|  | 839af3e90e | ||
|  | c059cdd0f2 | ||
|  | 0ba837e163 | ||
|  | 1ddcf370a7 | ||
|  | e0559e4fda | ||
|  | eeefbfd38d | ||
|  | 60ba4943ec | ||
|  | ba4ac17425 | ||
|  | 3965d3ba83 | ||
|  | 3435f24770 | ||
|  | 31672ff60e | ||
|  | 6e619f8927 | ||
|  | 2ccdb165e3 | ||
|  | db8eab04e3 | ||
|  | 4e2e8954dc | ||
|  | a25fe81b9e | ||
|  | bce3ac2c73 | ||
|  | 52b70fbbfa | ||
|  | 08b540dd78 | ||
|  | 22e91979bb | ||
|  | e3730ecfc3 | ||
|  | 9cfc9b3ee2 | ||
|  | c0ff3805c8 | ||
|  | 49ebd19ab1 | ||
|  | 79bcc98e9b | ||
|  | a58980fe82 | ||
|  | fe67a86a5f | ||
|  | 4d85bb13d1 | ||
|  | 0501c06745 | ||
|  | abb2e6ea9b | ||
|  | a99a30d720 | ||
|  | 0670c8f60f | ||
|  | dfdcb92f3d | ||
|  | bc9b5706e9 | ||
|  | 64c37a20d1 | ||
|  | 6d2d4f72ac | ||
|  | 4c151970e6 | ||
|  | e65e815aae | ||
|  | db3fb23de4 | ||
|  | 5c9adc4052 | ||
|  | b8c8c29ee4 | ||
|  | 47c0c71e19 | ||
|  | 7d26a86071 | ||
|  | 556d880951 | ||
|  | 4ee50ed6de | ||
|  | b1b5a9d8fa | ||
|  | 62d8848bee | ||
|  | c63b16cf75 | ||
|  | d32a6f15bf | ||
|  | 918abadb6c | ||
|  | 7f5adb135d | ||
|  | b1ce301520 | ||
|  | cd93201e46 | ||
|  | c9aaf5fb24 | ||
|  | fdf1e32962 | ||
|  | 36d336618e | ||
|  | 013f27e3e6 | ||
|  | 1b3f8a4c18 | ||
|  | dd8ef51fa1 | ||
|  | 11e8d26606 | ||
|  | 1e954bc8ef | ||
|  | 720eb0e91c | ||
|  | 106763ef9a | ||
|  | 10019a9d96 | ||
|  | 4515bcf289 | ||
|  | aa8728a2ab | ||
|  | f2d3b3661b | ||
|  | 24b598b1be | ||
|  | 0d98ee8916 | ||
|  | 3eca5ad9a1 | ||
|  | ed2465fd30 | ||
|  | 6d21e61889 | ||
|  | 983312d14d | ||
|  | 2e1271fe36 | ||
|  | 15e53c9839 | ||
|  | 115d48497e | ||
|  | a31948f3b7 | ||
|  | a12106eb52 | ||
|  | dd9f42172f | ||
|  | 3d8e149668 | ||
|  | f557647525 | ||
|  | 1efaf2cde0 | ||
|  | 202aea4dda | ||
|  | eaefa1ac5d | ||
|  | fd49174b1a | ||
|  | 342605bb44 | ||
|  | a9851f5e95 | ||
|  | 848b39b5a0 | ||
|  | de372ce095 | ||
|  | 8bbae4b10b | ||
|  | cff2eda198 | ||
|  | 7a75b47da6 | ||
|  | 79430340e5 | ||
|  | 4494c25df7 | ||
|  | 763d659ee2 | ||
|  | 54086f86d2 | ||
|  | 9195a23c95 | ||
|  | 739ba0fbcc | ||
|  | 93ac41e917 | ||
|  | 1928af2a42 | ||
|  | 45e6585e77 | ||
|  | 8d6fbe1a89 | ||
|  | 375b420c35 | ||
|  | 887b48bd1d | ||
|  | 0794a2e526 | ||
|  | a859e44630 | ||
|  | 1c1a248277 | ||
|  | e0e2165c8e | ||
|  | 957f8315e3 | ||
|  | d279ed7dd6 | ||
|  | 827480b9d6 | ||
|  | 1a0af097a6 | ||
|  | d408fc2864 | ||
|  | bba03eef2f | ||
|  | 352f7d7f2b | ||
|  | 0f07768d6b | ||
|  | a6a2be6e37 | ||
|  | e840cc8b91 | ||
|  | ff17105386 | ||
|  | d82f7b9205 | ||
|  | 01b09aab43 | ||
|  | f0153d801e | ||
|  | 319b2d8f32 | ||
|  | 419675cd2b | ||
|  | 9dd273626a | ||
|  | 2997acf9dc | ||
|  | 1ee9677b8a | ||
|  | 9c14c897f5 | ||
|  | dc3e37956b | ||
|  | eb283dcbc6 | ||
|  | fec2b39df3 | ||
|  | 1e1b8cc2d5 | ||
|  | 8a902d7e58 | ||
|  | 1a0d994305 | ||
|  | 597986b711 | ||
|  | ba0a843482 | ||
|  | 0ad0f9e094 | ||
|  | f93a548fe2 | ||
|  | 84b0920fe0 | ||
|  | a3d7f70d45 | ||
|  | 99b7ce7bf5 | ||
|  | 819e3b9661 | ||
|  | cac468586a | ||
|  | afc8c05f7f | ||
|  | 886e528490 | ||
|  | 06691a0794 | ||
|  | c61da238e1 | ||
|  | e07419b4ba | ||
|  | cecc0e9dc8 | ||
|  | 4d4d7c1fb3 | ||
|  | e50e7ee119 | ||
|  | 0d15d01b45 | ||
|  | 7972728e7c | ||
|  | d4d430ee80 | ||
|  | b2155fde1a | ||
|  | 0033b9eeb5 | ||
|  | 3d25b06fbc | ||
|  | 32752bc3dd | ||
|  | f1fd43b61c | ||
|  | 38fda754a1 | ||
|  | dc4e40a2f6 | ||
|  | 9abda62c5b | ||
|  | cd5c37fe1c | ||
|  | bce8cac1f4 | ||
|  | 4171d0c301 | ||
|  | 2edd956853 | ||
|  | d77b03d6c9 | ||
|  | 4d5a88661f | ||
|  | 0b9b1ccd0b | ||
|  | d5ef8e037d | ||
|  | fd09a32d5e | ||
|  | afc5de69d4 | ||
|  | 2adec6ef66 | ||
|  | 5829d87313 | ||
|  | 4422423315 | ||
|  | 6c88b6c660 | ||
|  | ccca1401ae | ||
|  | 39270f9647 | ||
|  | 3b6a147653 | ||
|  | fd69075a8b | ||
|  | dfed228991 | ||
|  | 5403c6122c | ||
|  | ec76533493 | ||
|  | fbdc356b7c | ||
|  | 709e1afd31 | ||
|  | 217bbd0dcb | ||
|  | e32f9edc3d | ||
|  | 282029eb45 | ||
|  | 0ae88174b8 | ||
|  | 42fdc445d0 | ||
|  | 48416fcdc1 | ||
|  | 5dab79f1c7 | ||
|  | cfe2d71862 | ||
|  | db03ac1596 | ||
|  | 36a1405360 | ||
|  | 85d1fe36e1 | ||
|  | 0148ff5ea2 | ||
|  | 89f096d68e | ||
|  | db9a15e2fa | ||
|  | 84ae15e8d1 | ||
|  | f69451140f | ||
|  | ca897d8d15 | ||
|  | 4cacc0ee7d | ||
|  | 93148f9334 | ||
|  | 9ae2f02842 | ||
|  | bc63df367d | ||
|  | 3f76b672f2 | ||
|  | c79f1d5f37 | ||
|  | db023c4448 | ||
|  | 48f66c5cb4 | ||
|  | f54cd61ba6 | ||
|  | 011ec46dae | ||
|  | 6c91562aa9 | ||
|  | a3ce036dc0 | ||
|  | c82ecd6656 | ||
|  | 7ce37c9842 | ||
|  | 6e4baa664d | ||
|  | 59ffb010c4 | ||
|  | 2edb216b24 | ||
|  | 7835e2a762 | ||
|  | f8c9d0c018 | ||
|  | 2965b52563 | ||
|  | 05762487ff | ||
|  | b2380fcc48 | ||
|  | 40ec4f631c | ||
|  | f9238f838c | ||
|  | 3dd756c2c1 | ||
|  | a92bdc094d | ||
|  | 9b367aa0a1 | ||
|  | 2201a47d95 | ||
|  | bdb578fda2 | ||
|  | 6765f24184 | ||
|  | 5ec0df6fe1 | ||
|  | 594fbed146 | ||
|  | 20e2e324e1 | ||
|  | f33e774f4b | ||
|  | dbdce70a8e | ||
|  | b41f609fe4 | ||
|  | 424f396e42 | ||
|  | b1c01d2ac9 | ||
|  | fed21338fc | ||
|  | 987fe8b638 | ||
|  | 535c4372ca | ||
|  | ac1f36ae76 | ||
|  | b1442a1a97 | ||
|  | 6628e7769e | ||
|  | 5fadbc7f97 | ||
|  | 095026b459 | ||
|  | 496c8d01fa | ||
|  | 63574298ce | ||
|  | 8c1a5f033e | ||
|  | 7e3141512a | ||
|  | c4510327d4 | ||
|  | 88fc2bb3e1 | ||
|  | 75a6913f4e | ||
|  | 97472070c3 | ||
|  | 5d4fd6055e | ||
|  | 83f4e5b457 | ||
|  | 1523a4953f | ||
|  | 429139be78 | ||
|  | 0307c0366a | ||
|  | f698db8346 | ||
|  | b690ccfc20 | ||
|  | 86e97d9f87 | ||
|  | 4a7a570953 | ||
|  | 0b1ce57fd1 | ||
|  | eb39bfad81 | ||
|  | 77533a2090 | ||
|  | 414bc9cc44 | ||
|  | 180d55d135 | ||
|  | 458baea830 | ||
|  | aaeec65415 | ||
|  | 3a821c040e | ||
|  | 31fdb438bb | ||
|  | 8db00f063d | ||
|  | 8cca58b800 | ||
|  | 9f2e60598d | ||
|  | 78af10f81b | ||
|  | 025ac59005 | ||
|  | 2b9605e8f5 | ||
|  | 333091a0d3 | ||
|  | 012ff9982c | ||
|  | 887e1d5d61 | ||
|  | 3aca463e7e | ||
|  | b7255dac54 | ||
|  | a3158f498f | ||
|  | 95ff997d1d | ||
|  | 80520d4ed7 | ||
|  | 1fbf5728e1 | ||
|  | 216b6b3efd | ||
|  | 557f287005 | ||
|  | 7548112578 | ||
|  | 323685d4c9 | ||
|  | 4900b15a65 | ||
|  | adc02e52ad | ||
|  | 4bc79321a7 | ||
|  | c0d270947f | ||
|  | 8b4677dca3 | ||
|  | 44482a809e | ||
|  | 90d8fab02e | ||
|  | 337d248c5d | ||
|  | 62a636c887 | ||
|  | bbd12ca7aa | ||
|  | 02f858e5c9 | ||
|  | 536a126886 | ||
|  | 2a42fdea85 | ||
|  | eb77e55fe6 | ||
|  | edd643b226 | ||
|  | 4f7f3b5a50 | ||
|  | 1b611e7cd8 | ||
|  | 5454ec8f9b | ||
|  | d2d528d214 | ||
|  | a00d4b7845 | ||
|  | 0eeefc4c0d | ||
|  | 0d8600ed6d | ||
|  | 35cf511d45 | ||
|  | b88fe43808 | ||
|  | 9c72fc1d2b | ||
|  | e176789891 | ||
|  | 5e3369aba3 | ||
|  | 7b0fcd79a0 | ||
|  | 0ed40c04c7 | ||
|  | 7da36611dc | ||
|  | 49aeee3017 | ||
|  | 571cd5a94f | ||
|  | a044570365 | ||
|  | c18595ce31 | ||
|  | a06d6839e1 | ||
|  | 22ba3c7b41 | ||
|  | e84ecd9e42 | ||
|  | db5e7962c9 | ||
|  | 4782f379e2 | ||
|  | 8762b5aad4 | ||
|  | 147d76d2aa | ||
|  | a5aedfee75 | ||
|  | 2a4c743edd | ||
|  | a9d820ed2f | ||
|  | fa059a59a8 | ||
|  | dc8f5ef279 | ||
|  | e5e30dc73d | ||
|  | ae94917e76 | ||
|  | fedb3704f3 | ||
|  | ea18f8e19b | ||
|  | cd93b0470b | ||
|  | 4665b5aecf | ||
|  | 1f9b9c6235 | ||
|  | 3f4c43456f | ||
|  | 10a3ba33a5 | ||
|  | db0beacf02 | ||
|  | a07023d613 | ||
|  | 900c634af1 | ||
|  | 48d9b570b9 | ||
|  | 207ddca859 | ||
|  | 823b00705e | ||
|  | 4fb0ddedc7 | ||
|  | 31b3571d31 | ||
|  | ee373a2721 | ||
|  | 685bc7ae83 | ||
|  | bc6772282f | ||
|  | d0d0c1e5e5 | ||
|  | 1ed598ada6 | ||
|  | b003ae7270 | ||
|  | 18a4a3e21c | ||
|  | 72a41480ba | ||
|  | 6e221abda6 | ||
|  | e7d8b84581 | ||
|  | 7a84430e84 | ||
|  | 7e7274b002 | ||
|  | e27183d54f | ||
|  | f49c31ddb2 | ||
|  | ac959238aa | ||
|  | 563b6561a5 | ||
|  | bc26690cbf | ||
|  | 4f56896f60 | ||
|  | 5158d34c2d | ||
|  | 5c63f0b7e3 | ||
|  | 1b3fa825f3 | ||
|  | ef182f4b64 | ||
|  | b706479c9b | ||
|  | 751c4fe7ef | ||
|  | d09baef532 | ||
|  | 778244e436 | ||
|  | f6cf83aebf | ||
|  | e6901382a6 | ||
|  | 75c22b585e | ||
|  | 5018d3b5cb | ||
|  | 9eeacf2cfc | ||
|  | 9c25d59b82 | ||
|  | 4550133c81 | ||
|  | 8a5921e4bc | ||
|  | 470aa36c91 | ||
|  | 1fbcff5fcc | ||
|  | 6fb06af9ff | ||
|  | 62941d65a9 | ||
|  | 18fe170698 | ||
|  | c2cd4d5d15 | ||
|  | 69da2ac0c7 | ||
|  | e08e69719d | ||
|  | 5628024d45 | ||
|  | 9d46d25d03 | ||
|  | 836326f31e | ||
|  | 34fe80f9d9 | ||
|  | 15ae133662 | ||
|  | c405a5d5b3 | ||
|  | 7acff3b938 | ||
|  | 7099be8f44 | ||
|  | 86e8c36a75 | ||
|  | bc6fe86faa | ||
|  | 3bcab11310 | ||
|  | 3c8b92675f | ||
|  | 0f19d74cb1 | ||
|  | d796a2a768 | ||
|  | f962adbb52 | ||
|  | 3479d0ee30 | ||
|  | 70a0590ece | ||
|  | 8414c57026 | ||
|  | ae2e7f0603 | ||
|  | 7177c3b393 | ||
|  | 11f40ba93b | ||
|  | 273511037a | ||
|  | 56d64f23bf | ||
|  | cfbeca5e65 | ||
|  | aaf9b56084 | ||
|  | e0a953e27e | ||
|  | f7c1e5f60d | ||
|  | 84bf81ac31 | ||
|  | 6a67a8c574 | ||
|  | 0fad9eaee4 | ||
|  | d64d33ed07 | ||
|  | 0e8fdf49d0 | ||
|  | f147256697 | ||
|  | dbe275ce72 | ||
|  | 649cd608c1 | ||
|  | 87c63e995b | ||
|  | cd49c5bf66 | ||
|  | c3ca9468d1 | ||
|  | 89576aa2c1 | ||
|  | 630dbab749 | ||
|  | 8e95a2a603 | ||
|  | 6a1c94d48d | ||
|  | 578a9a3332 | ||
|  | 122fe8a20d | ||
|  | d32f607aba | ||
|  | 25d9591416 | ||
|  | 33f41cc68b | ||
|  | d8bee53822 | ||
|  | 0866f47904 | ||
|  | d230325569 | ||
|  | 8e7930a604 | ||
|  | 1dde89db69 | ||
|  | 350d0a6495 | ||
|  | 42e922d587 | ||
|  | 57c002f324 | ||
|  | e5fb684ac1 | ||
|  | 84abdc7b2d | ||
|  | db79a4a14b | ||
|  | f1b30c5aff | ||
|  | 4db2593801 | ||
|  | ad685d2153 | ||
|  | cf9dd7cf5e | ||
|  | f10d82dc30 | ||
|  | 5ec942fb2a | ||
|  | 2897cfb556 | ||
|  | 5484869af9 | ||
|  | 90cc3a0f05 | ||
|  | 99e45f71c2 | ||
|  | 488d246ada | ||
|  | 8189910b5a | ||
|  | de317b8e01 | ||
|  | 436cf94595 | ||
|  | 145c999762 | ||
|  | c82b46032a | ||
|  | cf9fa94eaa | ||
|  | d5139fef22 | ||
|  | f8964db41c | ||
|  | 052169695c | ||
|  | f9a8a94fd1 | ||
|  | 880d9bb33f | ||
|  | 68aa3eb1b9 | ||
|  | 39dbb9dad8 | ||
|  | ac7acf2441 | ||
|  | 87ce5770b7 | ||
|  | 24f3c8c29e | ||
|  | cf578d50ec | ||
|  | 6c2e4110ad | ||
|  | 01280bbd06 | ||
|  | 0f1b7a527b | ||
|  | 965c7e1200 | ||
|  | abea4f481c | ||
|  | 71191eae5c | ||
|  | 03d4efc5c0 | ||
|  | 22c38019b2 | ||
|  | 7cd8194c99 | ||
|  | b4747ad67f | ||
|  | bb6db55686 | ||
|  | 244cd8f94f | ||
|  | ba856910e0 | ||
|  | d00e023894 | ||
|  | 86b4b128a9 | ||
|  | 35bd06a9a0 | ||
|  | bdc7574fd5 | ||
|  | a7cac2463c | ||
|  | 474bc8823e | ||
|  | 95f6b0c06e | ||
|  | dc205333cd | ||
|  | 4de96ea715 | ||
|  | c94f02648c | ||
|  | 2ba0dd20fb | ||
|  | 389dc22856 | ||
|  | 823c8af1ab | ||
|  | 286562d202 | ||
|  | b83a1876ba | ||
|  | ed2a931ae3 | ||
|  | f77190f477 | ||
|  | 2d3335fa48 | ||
|  | d52b3fd3fe | ||
|  | 5a945afdc6 | ||
|  | 8b65ad0237 | ||
|  | 6d74246c91 | ||
|  | 9d81c953c3 | ||
|  | 97e41de23f | ||
|  | d57543b220 | ||
|  | 13cd91bffb | ||
|  | 2d170dfed8 | ||
|  | 744ac0eb81 | ||
|  | 057983ce3e | ||
|  | aadc34ab4d | ||
|  | d9c4af46ed | ||
|  | cdd0024bad | ||
|  | 6e331c523f | ||
|  | f7712c77b8 | ||
|  | fd436c316a | ||
|  | 7120f7df54 | ||
|  | 1d30bf8af4 | ||
|  | 40c70e12dd | ||
|  | 31b6eb916f | ||
|  | 09e7a582de | ||
|  | b8aec00dee | ||
|  | 174f5a3a49 | ||
|  | 758d469679 | ||
|  | 542bdaa740 | ||
|  | 14bd66805e | ||
|  | 01c2d76c54 | ||
|  | 40cd0b1dd2 | ||
|  | 5dad791818 | ||
|  | 3743a6858b | ||
|  | 409a8d3678 | ||
|  | 94084178d9 | ||
|  | 3c80245275 | ||
|  | 16c4b2a572 | ||
|  | 0cf1e72ed1 | ||
|  | 029346d322 | ||
|  | 9e959f9bdd | ||
|  | 3ec8c63e28 | ||
|  | ceeb1eca9d | ||
|  | 5800560602 | ||
|  | a840a56e02 | ||
|  | 8704f4e24e | ||
|  | 459a5a5b1f | ||
|  | afc28c54ac | ||
|  | 6772b45ea6 | ||
|  | 7defd4dab0 | ||
|  | db326a14b3 | ||
|  | 0abf2e237e | ||
|  | d3a2b52363 | ||
|  | de81594179 | ||
|  | 06bdf8b461 | ||
|  | d784303591 | ||
|  | 52d2c31427 | ||
|  | 9bc8e56458 | ||
|  | 489c728793 | ||
|  | 01eaadfa53 | ||
|  | dddd2f9202 | ||
|  | 31709134c9 | ||
|  | 456efad714 | ||
|  | 2112fc571a | ||
|  | 0c4379ff0f | ||
|  | a690b36478 | ||
|  | 6f5ed95f71 | ||
|  | 251ee5f5a2 | ||
|  | 9ab1d88a91 | ||
|  | 5d3d9f57fe | ||
|  | 0889882255 | ||
|  | 2a1f78f95a | ||
|  | 6faaa1a0cc | ||
|  | 77dd12a028 | ||
|  | 6a954445f1 | ||
|  | 9500e898c6 | ||
|  | c5989d4350 | ||
|  | 8f782be41d | ||
|  | afcc447a64 | ||
|  | 8cfcba83ae | ||
|  | a8315726ce | ||
|  | da668c80b2 | ||
|  | 55455ac21f | ||
|  | 74adacf96a | ||
|  | a384b41308 | ||
|  | 048a329afc | ||
|  | 3c3d16e794 | ||
|  | d95b544dfd | ||
|  | 5d9ea7b91b | ||
|  | 500289229a | ||
|  | 21d62387ae | ||
|  | 3bbfb30dcb | ||
|  | 819fbc6ed5 | ||
|  | 53e7c8fa34 | ||
|  | 35d13cad96 | ||
|  | c190fc702e | ||
|  | cd0ed7b509 | ||
|  | 24af685db1 | ||
|  | d7553ded6c | ||
|  | 884d5a7fc8 | ||
|  | a920074468 | ||
|  | 5ab342e298 | ||
|  | c99f525821 | ||
|  | dff004d695 | ||
|  | 6f53e4b536 | ||
|  | 9d3fe84135 | ||
|  | e5f7ae3878 | ||
|  | 97162d9a53 | ||
|  | d0b99cb260 | ||
|  | fa22cc2e20 | ||
|  | 9904255490 | ||
|  | f75c15b477 | ||
|  | 9404dcab69 | ||
|  | c4d4403955 | ||
|  | a0bb2dc907 | ||
|  | ed774a5691 | ||
|  | 78cedddbde | ||
|  | 3640dc2fa3 | ||
|  | d3c619e3d3 | ||
|  | c158759c11 | ||
|  | b49362420c | ||
|  | aab76646ee | ||
|  | 259245d412 | ||
|  | 717180a8eb | ||
|  | 12811483be | ||
|  | 822aa2a352 | ||
|  | 9d788d4d9c | ||
|  | d405cb8dd9 | ||
|  | 5d3e57094a | ||
|  | e28d3f8cbd | ||
|  | 182494a5b7 | ||
|  | 9487820c32 | ||
|  | 03d00c16f8 | ||
|  | 57a38a00d9 | ||
|  | 779b8679fd | ||
|  | d0143d6f3e | ||
|  | 7917c3fc15 | ||
|  | 81de913b77 | ||
|  | 0e3798cadb | ||
|  | 7447482608 | ||
|  | f9b185caa5 | ||
|  | 4761ce4b45 | ||
|  | 9f31af4c20 | ||
|  | ab448cdb57 | ||
|  | 22c4076818 | ||
|  | 6e8bd97709 | ||
|  | 7dd128a1a8 | ||
|  | dfd422a386 | ||
|  | 6f434cd94a | ||
|  | a82f2fec18 | ||
|  | 234115f384 | ||
|  | c522618a4b | ||
|  | 1c65c56970 | ||
|  | c6cff13038 | ||
|  | f25b101161 | ||
|  | 6a866e208f | ||
|  | 11b1e5abd7 | ||
|  | f44c387988 | ||
|  | b6629080ee | ||
|  | 4022dd564b | ||
|  | c848ce66c5 | ||
|  | 26b4c34778 | ||
|  | 7eff83d689 | ||
|  | 125fb7fbdb | ||
|  | 01be5511e5 | ||
|  | 4b45c6e35a | ||
|  | 7f831c1f4d | ||
|  | d6778847c9 | ||
|  | 9a96645b53 | ||
|  | ffa1b19e26 | ||
|  | 6f98b140a8 | ||
|  | e83d1a26e6 | ||
|  | b237d68c47 | ||
|  | 1027762816 | ||
|  | 42893fc3bd | ||
|  | a479761be5 | ||
|  | 6d7265d966 | ||
|  | 32048b7658 | ||
|  | 08f79c6b93 | ||
|  | 699a2268d6 | ||
|  | 410f9c485e | ||
|  | 8561e5e38e | ||
|  | 17617fe839 | ||
|  | 7f4173ab22 | ||
|  | 84236edaf8 | ||
|  | 370dc2d727 | ||
|  | 211b07a2e2 | ||
|  | 9f67ba6a38 | ||
|  | 03798fd604 | ||
|  | 7bb4897b9f | ||
|  | 4b0e97e666 | ||
|  | 5b655dd4cd | ||
|  | 023a61c0e5 | ||
|  | 38cc6383b7 | ||
|  | 77ac863bb8 | ||
|  | fdab219755 | ||
|  | f31e8d08cd | ||
|  | 224c8ec0fa | ||
|  | 309c19ef63 | ||
|  | 13aad7e8b4 | ||
|  | 6f36d0d06c | ||
|  | 76d734a4bd | ||
|  | b14f29b5b7 | ||
|  | c57b30e342 | ||
|  | f6023a7c76 | ||
|  | 6357a2d9b8 | ||
|  | 7e3a1a8b18 | ||
|  | 5f1b8f71f3 | ||
|  | cca8bb9092 | ||
|  | 647314d3cc | ||
|  | 30e6773617 | ||
|  | 08774dc558 | ||
|  | 481618826d | ||
|  | befcada36a | ||
|  | b71bf9332c | ||
|  | 1303c93139 | ||
|  | 29c8c75492 | ||
|  | 862d83c691 | ||
|  | f18eeb4da8 | ||
|  | d40fed016f | ||
|  | 76dc3ddf56 | ||
|  | d80d9a4c4e | ||
|  | 281ee1c2bf | ||
|  | 65e976198e | ||
|  | a0d668e850 | ||
|  | f7d624e684 | ||
|  | f5c395adb2 | ||
|  | 09192b4d6e | ||
|  | 74ec3783e7 | ||
|  | 1c38ce8245 | ||
|  | 702cfe15be | ||
|  | 54d790828f | ||
|  | aff35fea29 | ||
|  | 25a82bcbe3 | ||
|  | cb58100587 | ||
|  | 9fbe96fd7c | ||
|  | 98cd400443 | ||
|  | 873e699f6d | ||
|  | 9a8f6c824f | ||
|  | a98888ad07 | ||
|  | db98500b72 | ||
|  | 3feee09cfe | ||
|  | 4a1cd0d391 | ||
|  | edb5071d3b | ||
|  | e9509aa5e6 | ||
|  | 5e6ca1b72d | ||
|  | 543bf2ffbd | ||
|  | 15a7a4c38b | ||
|  | 640d07bf35 | ||
|  | e5ecc2b942 | ||
|  | cfd8fe40f4 | ||
|  | abba6e0642 | ||
|  | ec94fb89a2 | ||
|  | bb167efa7b | ||
|  | 2a550ef96d | ||
|  | 03ed7d73fc | ||
|  | 446852db3b | ||
|  | 7c90b57e87 | ||
|  | 6339e2588b | ||
|  | af6687405b | ||
|  | a2bfad1c29 | ||
|  | 645aa55abc | ||
|  | 05329c885a | ||
|  | b3fed93a74 | ||
|  | 2c6fad0ea7 | ||
|  | 57854c2231 | ||
|  | a8cf4293e0 | ||
|  | ba70dce803 | ||
|  | 5b4c3ace56 | ||
|  | 2ade7a15e2 | ||
|  | e83f71d678 | ||
|  | 412c91cb6b | ||
|  | aa44167319 | ||
|  | dd5700e8b3 | ||
|  | ef7fc430d7 | ||
|  | f1bcb6c634 | ||
|  | 4a4eb17d08 | ||
|  | 8afc267c68 | ||
|  | 6457ab31b6 | ||
|  | 306dfa2043 | ||
|  | 424bdade0b | ||
|  | 10857e3321 | ||
|  | 85a4e47879 | ||
|  | 759e49f025 | ||
|  | 43924e31b8 | ||
|  | 3b34fcf59f | ||
|  | ba7253eaf7 | ||
|  | be23682a30 | ||
|  | 3a5dce4c92 | ||
|  | 22d7e60d0e | ||
|  | 5752156c9e | ||
|  | a30215a530 | ||
|  | f9c8c1b964 | ||
|  | 5650f67ef5 | ||
|  | 5ec25dfb94 | ||
|  | ef16682725 | ||
|  | 883486cc67 | ||
|  | f367f9b747 | ||
|  | a3d987fa73 | ||
|  | 2d48685673 | ||
|  | 9b21ace1e9 | ||
|  | be2c03fa96 | ||
|  | f5585e9252 | ||
|  | 4d534dd7e4 | ||
|  | c8584e1cce | ||
|  | 84a1de464c | ||
|  | 3966f3d319 | ||
|  | e6166cf711 | ||
|  | 2285712834 | ||
|  | 53cb6128e8 | ||
|  | 8c317baf19 | ||
|  | 8cac933c71 | ||
|  | 03e61a4bf8 | ||
|  | 71446a76b2 | ||
|  | 28db8d6c7c | ||
|  | 786e33d7d5 | ||
|  | b140d6c50e | ||
|  | 64a95abdee | ||
|  | 57f926be17 | ||
|  | 4933b67959 | ||
|  | 370b4f1b9e | ||
|  | f3b7baa84e | ||
|  | eafdb2c807 | ||
|  | a91fa821ab | ||
|  | 37ef162cda | ||
|  | 770928acfc | ||
|  | d0f3570219 | ||
|  | 3d07c2605f | ||
|  | c350798528 | ||
|  | 6bc3cc0bec | ||
|  | 2e3e5fcc81 | ||
|  | dfdb10f6de | ||
|  | 5cbe5909eb | ||
|  | 04d52b450b | ||
|  | a586a89547 | ||
|  | 1905eacf15 | ||
|  | 858ec0d740 | ||
|  | 76cfd406ca | ||
|  | 9dbaad859d | ||
|  | 95d43e17b3 | ||
|  | 09a2dff8de | ||
|  | 57208f879a | ||
|  | 149638431d | ||
|  | 30d2940c67 | ||
|  | 5ee86fc5d0 | ||
|  | a03d0e2c3f | ||
|  | 8bd367d58d | ||
|  | bc633e03aa | ||
|  | 797d0f1ef1 | ||
|  | 1be3e86aa0 | ||
|  | e56dd38021 | ||
|  | 410904bef1 | ||
|  | 026cc120e7 | ||
|  | ef2fda05cf | ||
|  | 92277e3ae2 | ||
|  | fbc34d70b0 | ||
|  | 91dcddbdf7 | ||
|  | 874f42ad6c | ||
|  | 1989ef4ebc | ||
|  | 4f4c72c065 | ||
|  | 666cc72661 | ||
|  | 4524e8f5c9 | ||
|  | bd07a29886 | ||
|  | a0d865492e | ||
|  | de27790de8 | ||
|  | 9c910b7be2 | ||
|  | 7f23ab94e2 | ||
|  | 77dc036c8f | ||
|  | aa6e8d82ce | ||
|  | 3010285bb3 | ||
|  | aaad3252f8 | ||
|  | 9065f534d8 | ||
|  | 52361c94e5 | ||
|  | 798be60fef | ||
|  | 6294154b15 | ||
|  | 6594fe077d | ||
|  | 582706cde6 | ||
|  | 6537cbdc17 | ||
|  | 53959459bb | ||
|  | 22d6121099 | ||
|  | 48d7f6f2f4 | ||
|  | 9fd4ddc490 | ||
|  | a4d2fddbb2 | ||
|  | c54a3f2721 | ||
|  | 04c0dba697 | ||
|  | 5406e3b7c5 | ||
|  | 6b624b7d00 | ||
|  | 2d364d4d80 | ||
|  | 1f27bf3774 | ||
|  | d30a2653b5 | ||
|  | 3086822cd2 | ||
|  | 2c08336490 | ||
|  | 5936ac58c2 | ||
|  | ded77e3f5c | ||
|  | 8a29df0a6c | ||
|  | 9db22babaf | ||
|  | c318c5ed61 | ||
|  | 61243c65cd | ||
|  | 4a5d5cb462 | ||
|  | cbf1447ebd | ||
|  | 30104441bf | ||
|  | b4a70804f0 | ||
|  | 74f6707bde | ||
|  | 223eb8c84d | ||
|  | 107d000606 | ||
|  | 43e05607af | ||
|  | 55793452d5 | ||
|  | 686ba37255 | ||
|  | 03ed19dad5 | ||
|  | ad2b6e5de1 | ||
|  | 767676d6ff | ||
|  | bc7a54c615 | ||
|  | 1bda393678 | ||
|  | bb5495c6bd | ||
|  | 484f905749 | ||
|  | e0d61a4336 | ||
|  | e643a16ba5 | ||
|  | 98fadec2b6 | ||
|  | 14f464ecb0 | ||
|  | 2ecdaf9bd4 | ||
|  | 707c898f66 | ||
|  | 69e4400774 | ||
|  | 695efde68d | ||
|  | 0c4b769011 | ||
|  | e53eff0634 | ||
|  | 6c75243a06 | ||
|  | efde37880b | ||
|  | 7d8f6381be | ||
|  | 3c361e3393 | ||
|  | 8440ecef5e | ||
|  | 6401f1b1c9 | ||
|  | 7487a7c988 | ||
|  | f44584fa10 | ||
|  | 7b32165614 | ||
|  | b0dc94d187 | ||
|  | 0383c4e1d8 | ||
|  | a8c5758222 | ||
|  | a7fabfd8cb | ||
|  | 5d5b575d16 | ||
|  | ac1373653c | ||
|  | b097aa787b | ||
|  | 723be0fe69 | ||
|  | f0597a03de | ||
|  | 65f0656f54 | ||
|  | 507ece15a5 | ||
|  | 30be4d1613 | ||
|  | 366e89bda0 | ||
|  | f159c3f768 | ||
|  | 8506d1d567 | ||
|  | 111829da46 | ||
|  | 605798073e | ||
|  | 8320f2b094 | ||
|  | df0d8d809b | ||
|  | 062886df64 | ||
|  | 148ea3aaa8 | ||
|  | ab5f66c13a | ||
|  | e65ffb8e68 | ||
|  | 949c1ab517 | ||
|  | 946d8ee046 | ||
|  | c54a8a2e10 | ||
|  | 31177e4f85 | ||
|  | 750f81b4b5 | ||
|  | 987ff02a45 | ||
|  | f5adaf813c | ||
|  | 78ff7dc7f0 | ||
|  | d1fced3324 | ||
|  | e7df9c289b | ||
|  | a78d7231a9 | ||
|  | ba7ae0002e | ||
|  | a090f7b839 | ||
|  | 34ed15a987 | ||
|  | cacec4c910 | ||
|  | 3e47d4e65b | ||
|  | 8b42fa150b | ||
|  | 60e660b9c7 | ||
|  | fe74f013e3 | ||
|  | 24c0c70f90 | ||
|  | 757f91ca89 | ||
|  | 5c34f7847e | ||
|  | de456f014e | ||
|  | d29565066d | ||
|  | 4d52c9233b | ||
|  | 6da1ca0cb9 | ||
|  | 2f02f1518a | ||
|  | e8863707de | ||
|  | 6a336dfc69 | ||
|  | 35dec1b9e4 | ||
|  | f148280c99 | ||
|  | 599fe39749 | ||
|  | 44f3fcb238 | ||
|  | af40fdb285 | ||
|  | 9daf8b825c | ||
|  | ef5d8ce367 | ||
|  | 4a199ab23b | ||
|  | 6f0f5a569d | ||
|  | 3172fbfde6 | ||
|  | e97a07a505 | ||
|  | 6579ad92da | ||
|  | ec2fad0cfa | ||
|  | 6196ac7995 | ||
|  | 095a861018 | ||
|  | 2449ed7765 | ||
|  | 117a0408d6 | ||
|  | a54b0223a3 | ||
|  | 44ee708ba5 | ||
|  | 58a20d0fb6 | ||
|  | 063078a02d | ||
|  | 01402fea50 | ||
|  | b7fc2d1147 | ||
|  | 43eeb7011c | ||
|  | d7901a4220 | ||
|  | 0c6271dabc | ||
|  | 2d4cf0c9f5 | ||
|  | 0646d0dd91 | ||
|  | 83e54b45a5 | ||
|  | 5cd87d3d27 | ||
|  | 689d8a80b5 | ||
|  | b1d82a92e7 | ||
|  | 4d65627a50 | ||
|  | ce3a68d817 | ||
|  | 409725be24 | ||
|  | b74f74a0d7 | ||
|  | 719d554430 | ||
|  | 13f54f4521 | ||
|  | 57dfc9cf42 | ||
|  | 57244a6823 | ||
|  | 8bdde01bef | ||
|  | 09bbd5a472 | ||
|  | 9154a74400 | ||
|  | 1399b84b32 | ||
|  | 2ddbb3a8fa | ||
|  | e46a6d1cc1 | ||
|  | b698ab9011 | ||
|  | 0a2572a5eb | ||
|  | 77d049cc3d | ||
|  | 7b8f053be2 | ||
|  | 2c850d5293 | ||
|  | 4056bbf10b | ||
|  | 896b04a846 | ||
|  | 93cda8b6ec | ||
|  | bb5e930684 | ||
|  | 43761fed2a | ||
|  | a636299680 | ||
|  | 08e5bd5b72 | ||
|  | 2f057bef5e | ||
|  | 5ab4f21444 | ||
|  | 9ec26ed481 | ||
|  | 29c9df1389 | ||
|  | 867e9c51d4 | ||
|  | 0170f7b42a | ||
|  | 74bb6ead95 | ||
|  | 303388e5cb | ||
|  | 8388779937 | ||
|  | fc7dfca452 | ||
|  | e5a1db2392 | ||
|  | 6790656af6 | ||
|  | b7477bdc15 | ||
|  | ffc61f31de | ||
|  | e612871ea7 | ||
|  | 7f40f09f10 | ||
|  | 456e42257c | ||
|  | 8618c271cf | ||
|  | 72ca1ccc23 | ||
|  | 075b4bef3f | ||
|  | b59fce4393 | ||
|  | 8674a25eb8 | ||
|  | 10bf8fd2cd | ||
|  | 57cb22ff3c | ||
|  | 0162abdcae | ||
|  | 5801171518 | ||
|  | bf1edbd1e2 | ||
|  | a8484d987d | ||
|  | 9b2147f608 | ||
|  | 32530b378e | ||
|  | a42905efa6 | ||
|  | c59745f9dd | ||
|  | b4ad9a5d08 | ||
|  | 3ead7a38b1 | ||
|  | bf90435200 | ||
|  | 9c181fa3d3 | ||
|  | 3af0b1eb90 | ||
|  | 7110c318ee | ||
|  | 49a552ccdc | ||
|  | 57685f17a9 | ||
|  | a1c09a463f | ||
|  | 194121760a | ||
|  | 6a987d46bf | ||
|  | e3db0b39b9 | ||
|  | 4d4f0ee188 | ||
|  | ac7334c167 | ||
|  | e7bdd69af0 | ||
|  | fefc655969 | ||
|  | 4dceaef60e | ||
|  | 6fc10dd3ae | ||
|  | 1ecd05a584 | ||
|  | 976acaca31 | ||
|  | b4e5131d59 | ||
|  | 49f7cfefd7 | ||
|  | fc365092f6 | ||
|  | 7f26240442 | ||
|  | db559bb20a | ||
|  | 52850faa15 | ||
|  | 57d9a6c836 | ||
|  | 752c880bfc | ||
|  | d83a354781 | ||
|  | 17dd81336d | ||
|  | eaa46a2575 | ||
|  | fc0ec1e71e | ||
|  | fb2f92df1d | ||
|  | 74adbb77b7 | ||
|  | 788e544e1d | ||
|  | 368a0d4d2d | ||
|  | 962b7222d0 | ||
|  | 17c1f54369 | ||
|  | 33ae38e71b | ||
|  | ef58af4bf1 | ||
|  | 3fad2db2f8 | ||
|  | 9feaeb28ca | ||
|  | 0075364715 | ||
|  | 99c5da5da5 | ||
|  | 22c957bc20 | ||
|  | 3316d59910 | ||
|  | a109ce1eca | ||
|  | e581a78d65 | ||
|  | 3c78f9900c | ||
|  | bd606943e6 | ||
|  | 6381666df4 | ||
|  | 736f1aa301 | ||
|  | b1a4eac7a8 | ||
|  | 8226a5276b | ||
|  | 77ad0bb12e | ||
|  | 9412b42206 | ||
|  | 2a91d87074 | ||
|  | 4a23617d79 | ||
|  | 0e2ceed74d | ||
|  | ed56aed8eb | ||
|  | 8d909cbdc0 | ||
|  | bf98943cbb | ||
|  | 6ff4552be2 | ||
|  | 1c7eb79370 | ||
|  | f095a75f1e | ||
|  | f70af6018c | ||
|  | 71b3b1ff4c | ||
|  | d9fefa0c6c | ||
|  | 3bfe922381 | ||
|  | a85cf17bf1 | ||
|  | dbb5a09918 | ||
|  | 93e5097f20 | ||
|  | dd53f2dc83 | ||
|  | 2b83c80593 | ||
|  | 6930f60c06 | ||
|  | 376b76e75c | ||
|  | 1ddd4509dc | ||
|  | 6af3f4f4cf | ||
|  | 6726c5f958 | ||
|  | d5a9c43cb2 | ||
|  | 19a5a6a4eb | ||
|  | 617a599ee9 | ||
|  | 25e2d4da44 | ||
|  | ad2e7218cb | ||
|  | 917637fa9b | ||
|  | b595ee1c0b | ||
|  | c8260a4a56 | ||
|  | d2eaff3204 | ||
|  | b65f5a844f | ||
|  | 95a69f99ba | ||
|  | 71d609895a | ||
|  | 9229630447 | ||
|  | eb18a0b7dc | ||
|  | 05ed5c0d74 | ||
|  | 41330ecc5e | ||
|  | 16fbcc6e36 | ||
|  | d87da9c7de | ||
|  | 94563b6017 | ||
|  | 34d22f7047 | ||
|  | e24d996fbe | ||
|  | 9b52617919 | ||
|  | efc1d46c89 | ||
|  | 9397833ceb | ||
|  | e9433e83cd | ||
|  | f3c58100a0 | ||
|  | 8900231d99 | ||
|  | c7a63b8a2b | ||
|  | 90e90672a4 | ||
|  | fa51e5c762 | ||
|  | 911f55d005 | ||
|  | d30eb4e570 | ||
|  | 67bcfb6947 | ||
|  | 3915a61b1e | ||
|  | c170d321e8 | ||
|  | 2802c476ee | ||
|  | 1050cebf7f | ||
|  | dad73465fc | ||
|  | 8e2ac98fe2 | ||
|  | 9aaf0c36d5 | ||
|  | 1cb07e9cfd | ||
|  | f1ccdf25b1 | ||
|  | 6dca497b27 | ||
|  | 42a83262a1 | ||
|  | 63ee9cbee6 | ||
|  | 3862f8ca7c | ||
|  | 4ada7cffd0 | ||
|  | a664ce4298 | ||
|  | 8d7b6c6905 | ||
|  | 16d22d404a | ||
|  | ccb24d5779 | ||
|  | 8795b45cb4 | ||
|  | 628d3bff45 | ||
|  | 0336bc9de9 | ||
|  | 033cb21797 | ||
|  | 09b98a45df | ||
|  | 38857ba29e | ||
|  | 1c7520ec8f | ||
|  | 362b9769b2 | ||
|  | b2d68bd3d2 | ||
|  | 0dc7e635d4 | ||
|  | 80e070a857 | ||
|  | cc203245e4 | ||
|  | 2f9a65fc93 | ||
|  | 62738e8001 | ||
|  | 5ecacf0c7f | ||
|  | 06b103c8d4 | ||
|  | d473b7bca8 | ||
|  | 50a1e81ba7 | ||
|  | d9885b1b64 | ||
|  | 0a9c8cada2 | ||
|  | 60f55f8461 | ||
|  | 7bedaea38f | ||
|  | 9e4b87e798 | ||
|  | 95bf59095c | ||
|  | e0f34a9720 | ||
|  | f3797c2a8e | ||
|  | 30cbcccc80 | ||
|  | f49c0d696f | ||
|  | 71f564ee5b | ||
|  | 4b0950aba5 | ||
|  | 8c3af822ec | ||
|  | 878a207d19 | ||
|  | 0537ad860a | ||
|  | 2cdbbb1aea | ||
|  | 7af977d36b | ||
|  | 9afff4cf30 | ||
|  | 48ba9734aa | ||
|  | 897fc59f72 | ||
|  | 947e44ae67 | ||
|  | e44843beba | ||
|  | 147482ea69 | ||
|  | 09091c5cf8 | ||
|  | 50827a5f69 | ||
|  | 2d6444c924 | ||
|  | 1d2675d9aa | ||
|  | ad98990a8e | ||
|  | 8e58c143f2 | ||
|  | 556a4a2395 | ||
|  | 5be987b40f | ||
|  | 066bc35e69 | ||
|  | 403779437c | ||
|  | fb806f61d4 | ||
|  | 6ce306661c | ||
|  | 3c08ff94d4 | ||
|  | a6afae2356 | ||
|  | 0eea7070a7 | ||
|  | 105c2b1eea | ||
|  | 82bb0e8dda | ||
|  | 8c01179075 | ||
|  | c9d9a96630 | ||
|  | 8f21c9a920 | ||
|  | 0ba7d05ea7 | ||
|  | 5a4c5b4155 | ||
|  | 55323fb497 | ||
|  | 7c082d2471 | ||
|  | f3cafcf983 | ||
|  | 75073e4aa6 | ||
|  | a3c23f650c | ||
|  | 0545cd5879 | ||
|  | c96506f22c | ||
|  | 49b2006824 | ||
|  | 8c6f96faab | ||
|  | a0e648abfd | ||
|  | 6350cd12fc | ||
|  | f2fab0677b | ||
|  | edffc52927 | ||
|  | d6e5e3d103 | ||
|  | 5be7a0ebf7 | ||
|  | 7f722fe7d3 | ||
|  | a01732ee9b | ||
|  | 85ac11b69b | ||
|  | 590cfb77a5 | ||
|  | f01dd16a27 | ||
|  | df49287e5f | ||
|  | c8ec8391ee | ||
|  | 3499e48064 | ||
|  | 2e379cb8a5 | ||
|  | f8ee3c2369 | ||
|  | c74fa11518 | ||
|  | ceec4455df | ||
|  | 17c9975c0b | ||
|  | 6c1cdff912 | ||
|  | 79f53f569d | ||
|  | ccb85cc719 | ||
|  | c0eff8a07f | ||
|  | 954626f157 | ||
|  | 17e7dfa4bd | ||
|  | 971f233fb7 | ||
|  | b12bc692af | ||
|  | 730301b34d | ||
|  | c443bcf43c | ||
|  | b77e7eeddc | ||
|  | 031b7b57a1 | ||
|  | 5123fab525 | ||
|  | 705b96c6f9 | ||
|  | 9ec582002b | ||
|  | ee79277774 | ||
|  | db02dc218e | ||
|  | b66ce1089e | ||
|  | ec0e70b599 | ||
|  | a273482f9d | ||
|  | 76cf8c4cf7 | ||
|  | 9691ecc839 | ||
|  | 59b2a86359 | ||
|  | fe7cd72cff | ||
|  | f0761fc570 | ||
|  | 90990aa19d | ||
|  | a3d3ce82e4 | ||
|  | b8e48113a3 | ||
|  | d4b1003a97 | ||
|  | efd83567c9 | ||
|  | 5563f373f7 | ||
|  | 15a36619fe | ||
|  | 38e54b626e | ||
|  | 8aa30fb56a | ||
|  | b764becd1b | ||
|  | 219370932e | ||
|  | 90afae186c | ||
|  | 84e49a809d | ||
|  | 1cfb9ff46a | ||
|  | f35026c74f | ||
|  | 5f2d3da8c5 | ||
|  | 4e61f32a28 | ||
|  | d7814c7011 | ||
|  | aa40668e84 | ||
|  | 3767e6e96f | ||
|  | 44976cef6c | ||
|  | eba4417947 | ||
|  | c99204d370 | ||
|  | 1bfc4335bb | ||
|  | 6b9c7485f1 | ||
|  | 737f3d78f2 | ||
|  | b1d5e1b5e3 | ||
|  | 8d92a5cc14 | ||
|  | fc455df92c | ||
|  | c0076ebfa1 | ||
|  | 5d607aa3cd | ||
|  | fa1b9a4098 | ||
|  | c8c4dbb409 | ||
|  | 16628e6cea | ||
|  | 7067c12991 | ||
|  | 7b47e241e0 | ||
|  | d1e46207a5 | ||
|  | 2a04b97cbd | ||
|  | e6c8ef59e0 | ||
|  | d3380f41de | ||
|  | 4ef1633969 | ||
|  | 57e593aab2 | ||
|  | 6461caacbb | ||
|  | e5531e2a93 | ||
|  | 329402a614 | ||
|  | 4656ed462e | ||
|  | 96ddad91a9 | ||
|  | 5eb40588d2 | ||
|  | 58def149aa | ||
|  | 0ee5743d75 | ||
|  | 7c266f3e81 | ||
|  | d7ce981cd1 | ||
|  | eadadf6299 | ||
|  | 8ac9fabd07 | ||
|  | 44c2b4b281 | ||
|  | 4cd97611e5 | ||
|  | da27380ab5 | ||
|  | 756e539661 | ||
|  | cde44e3172 | ||
|  | e79a4b34b0 | ||
|  | e9f0bdd72c | ||
|  | d080291150 | ||
|  | 06c69c56ba | ||
|  | d79710ba9d | ||
|  | c9bc7dd0b6 | ||
|  | ebc26c7421 | ||
|  | 3769425f6b | ||
|  | a50957443e | ||
|  | 63fa007af0 | ||
|  | a6a52a128b | ||
|  | 1ad58e1121 | ||
|  | 3f507a26fb | ||
|  | bfc368764a | ||
|  | 53fbce932b | ||
|  | a94195c6cd | ||
|  | 626c6d1124 | ||
|  | 471ab92bbb | ||
|  | fbccd12924 | ||
|  | e5928bbaea | ||
|  | 3c1597bc67 | ||
|  | 295019815e | ||
|  | 654a391250 | ||
|  | 9ee1465d3c | ||
|  | 52197cf4d2 | ||
|  | cfbb2afac5 | ||
|  | 8f154f65f9 | ||
|  | 7454664997 | ||
|  | 3393b7aedd | ||
|  | 133ccc95b5 | ||
|  | c392ff1cd3 | ||
|  | 30a0f831a5 | ||
|  | 541ea4dc63 | ||
|  | afc5e0e3e5 | ||
|  | bcb31df10d | ||
|  | 2192c4e269 | ||
|  | eec17858c4 | ||
|  | 6d696706be | ||
|  | 8cd88b6051 | ||
|  | 9dbf53fdb9 | ||
|  | 38b6963c8b | ||
|  | 7b6248983d | ||
|  | 4d418dee0e | ||
|  | 06fe319347 | ||
|  | 9dd7e3fb24 | ||
|  | d5a46396b0 | ||
|  | 5e84cb560d | ||
|  | 756c6f8560 | ||
|  | 6fa6ce35da | ||
|  | b14b97599d | ||
|  | db6f60d6fc | ||
|  | 25c348d7c8 | ||
|  | 2e4bf8b034 | ||
|  | c1490e2f7b | ||
|  | b004fe9556 | ||
|  | 67142ad046 | ||
|  | 3c3ec06b12 | ||
|  | 5b5caa8a16 | ||
|  | b2cba098bb | ||
|  | 1ec0d47f10 | ||
|  | f232606ec7 | ||
|  | fa28cea152 | ||
|  | c8da1647a1 | ||
|  | 505a0a8718 | ||
|  | 10d3496a17 | ||
|  | a13c755370 | ||
|  | 62f9996fd7 | ||
|  | edbcd8a1b2 | ||
|  | a5308d1689 | ||
|  | cbfe6e8fcc | ||
|  | 5571ff35d8 | ||
|  | 2a4819f3c8 | ||
|  | 7121866b13 | ||
|  | d6e05ad9e2 | ||
|  | 993e30a7de | ||
|  | 49cae61254 | ||
|  | 1ea4b2ea91 | ||
|  | bc1d6e1f90 | ||
|  | 9ec6e68d0c | ||
|  | 341bdc93e2 | ||
|  | 6fb3e1aa15 | ||
|  | f1f92eb2e2 | ||
|  | 8c2369d40f | ||
|  | a6d9fc58eb | ||
|  | f7cd471548 | ||
|  | 5f951faf32 | ||
|  | b228dfaf2c | ||
|  | 764858fa12 | ||
|  | 5ee976d276 | ||
|  | 8b28b6f2d3 | ||
|  | fe16df2e6f | ||
|  | 779047f8c9 | ||
|  | 094e9fb45d | ||
|  | 1458bd0e74 | ||
|  | d2cb05988d | ||
|  | 6e056767b4 | ||
|  | a10afb1b98 | ||
|  | bb6d3b6cfd | ||
|  | c75d4af4bc | ||
|  | 972dc39d00 | ||
|  | 9daac5c178 | ||
|  | dd2a3f40e1 | ||
|  | 78f76c1690 | ||
|  | 4788066a5f | ||
|  | 10e4254e7d | ||
|  | 0106e4df9d | ||
|  | 8ac718a3a2 | ||
|  | 46d45273a1 | ||
|  | 8da9ec3599 | ||
|  | 01fdf84d69 | ||
|  | cc78386e75 | ||
|  | 3755157c61 | ||
|  | 80f8436f0a | ||
|  | f88a4b7760 | ||
|  | de229b8ab0 | ||
|  | a3ba37e45e | ||
|  | 50c779b3c6 | ||
|  | 192372e1c3 | ||
|  | f88fd88c38 | ||
|  | 6e15145af1 | ||
|  | 4b5fad4e48 | ||
|  | 7a13e71c80 | ||
|  | 3c10943900 | ||
|  | 696b8811c2 | ||
|  | 9fd2c8602a | ||
|  | a3636a5af4 | ||
|  | f2e5f07718 | ||
|  | 16c6fdde60 | ||
|  | 2155c93426 | ||
|  | c394631e4c | ||
|  | 8b370b7cc1 | ||
|  | 607db9971c | ||
|  | 6768f64e2f | ||
|  | f1813b1cc6 | ||
|  | fb665bd0dd | ||
|  | 65dda2ef3d | ||
|  | b162b992af | ||
|  | 67a3a3d130 | ||
|  | 92cd9bf7d2 | ||
|  | bf97034485 | ||
|  | 1ded1fc509 | ||
|  | e0592c58b3 | ||
|  | 5ead2706b4 | ||
|  | 52ada4853c | ||
|  | c2b27a8298 | ||
|  | 3934c1d437 | ||
|  | e366b68ad3 | ||
|  | fb94fb980a | ||
|  | b10cc18f53 | ||
|  | a249de3b72 | ||
|  | d04e972d65 | ||
|  | b9f5a18a76 | ||
|  | d3f157f08a | ||
|  | 2294fdb496 | ||
|  | d7ba0e01a5 | ||
|  | b6172b53fd | ||
|  | 477ec611d5 | ||
|  | b6194edd67 | ||
|  | dcdbbb3ecb | ||
|  | 7ef99ee4e6 | ||
|  | 1ac1418286 | ||
|  | 8fc854f38e | ||
|  | 1c2360b335 | ||
|  | dd4477406b | ||
|  | 9d67bbb104 | ||
|  | d6c8e1df61 | ||
|  | 5ec7c8fece | ||
|  | 86b21eaf83 | ||
|  | 228486a971 | ||
|  | 88c0caab26 | ||
|  | 5cd4679419 | ||
|  | eeed5e0d19 | ||
|  | 369ab1e0b2 | ||
|  | 2e21519a10 | ||
|  | ecc001ed08 | ||
|  | cd96852696 | ||
|  | b9f7f30158 | ||
|  | ca5e423331 | ||
|  | fa9407089c | ||
|  | 66f28e193a | ||
|  | 0d93f89f5c | ||
|  | 154e9a2c47 | ||
|  | 84574a1257 | ||
|  | bf83527b64 | ||
|  | 12c53622a0 | ||
|  | d8f54cf891 | ||
|  | 625a671189 | ||
|  | 6ebdad3102 | ||
|  | 9a8f21aa03 | ||
|  | 291dd8edc2 | ||
|  | de4c1daf29 | ||
|  | 0b55d7d0d8 | ||
|  | 5d86fd8fdb | ||
|  | 1b76eb1f59 | ||
|  | b05678d8bf | ||
|  | 781f4971c6 | ||
|  | d02ac7b99a | ||
|  | b1b6c97f7c | ||
|  | baee28ab5c | ||
|  | 83edf68ff9 | ||
|  | c7588f91dd | ||
|  | 30b432adc5 | ||
|  | 7c9733eb5d | ||
|  | a223c3fea3 | ||
|  | d5250f4901 | ||
|  | 25f29f4712 | ||
|  | 382af5563d | ||
|  | 8cf3d165d3 | ||
|  | 0fd6ce546f | ||
|  | b881c372bc | ||
|  | 94c5e7deb0 | ||
|  | c344766f3c | ||
|  | 67895de0bc | ||
|  | ff00cb6990 | ||
|  | 2cc75c11ed | ||
|  | cd79e58eda | ||
|  | 6fa801f3d8 | ||
|  | 684eecba1d | ||
|  | da9cf7e5de | ||
|  | f57e7445fd | ||
|  | fba1388719 | ||
|  | 80ed029c17 | ||
|  | 34a74e81e3 | ||
|  | cb120ddb15 | ||
|  | f9ee4395b0 | ||
|  | 71f06d51ed | ||
|  | 217f70952f | ||
|  | f813d41a76 | ||
|  | d851289d8a | ||
|  | b115b8a2ea | ||
|  | d0f7067471 | ||
|  | be5b4c38a7 | ||
|  | d6d597e3dd | ||
|  | 84e348fade | ||
|  | 910054657e | ||
|  | 8357a11249 | ||
|  | 9b021ba057 | ||
|  | 317e588efd | ||
|  | b1d32a03c7 | ||
|  | ee6e6529ee | ||
|  | 9d944d6cf9 | ||
|  | 13635d281a | ||
|  | 2493c46970 | ||
|  | 63e4217271 | ||
|  | f4bd12e8e9 | ||
|  | df15f46900 | ||
|  | fb3a732361 | ||
|  | 2d74110feb | ||
|  | 19d102082d | ||
|  | d2af2c9487 | ||
|  | 82980149fa | ||
|  | a19bb7b909 | ||
|  | 9d98c3278d | ||
|  | 26376ac1c9 | ||
|  | 8459f99341 | ||
|  | e5bdb0e0b5 | ||
|  | 1106b7775a | ||
|  | ae2852156d | ||
|  | 44c6c36c43 | ||
|  | a81926503d | ||
|  | af13ccddda | ||
|  | 392e1bc2e8 | ||
|  | 9268d92c70 | ||
|  | bb3366c07d | ||
|  | d24d563ebc | ||
|  | 954bd9257b | ||
|  | 5d51a56c02 | ||
|  | f48648552e | ||
|  | edb9c3cc9f | ||
|  | 01dc83b936 | ||
|  | 3a8dff3a62 | ||
|  | 13b234ccba | ||
|  | e451e93664 | ||
|  | b4f9531475 | ||
|  | 3184ff75c4 | ||
|  | 43243f4d30 | ||
|  | c975a100b1 | ||
|  | 02bf389425 | ||
|  | bcb9a3dd04 | ||
|  | cce3baa275 | ||
|  | 2b48fad426 | ||
|  | d554b2bc94 | ||
|  | f66943de43 | ||
|  | 9d1e9bc2fb | ||
|  | 2d6a014920 | ||
|  | c1952bf257 | ||
|  | a10227eb03 | ||
|  | 475ae29b85 | ||
|  | 0b9cfc278b | ||
|  | b57b6b4fba | ||
|  | 7d948f7bc5 | ||
|  | 459023d171 | ||
|  | fd6570720a | ||
|  | 7831665417 | ||
|  | 7c9920d982 | ||
|  | cbdccf0a9c | ||
|  | 64fa83ec3f | ||
|  | faff865cfd | ||
|  | 742ab55a9a | ||
|  | 66e623fb2a | ||
|  | 4ab17ee965 | ||
|  | 7f48ca5132 | ||
|  | da983848b4 | ||
|  | bc03f7bad3 | ||
|  | a1c8bd3846 | ||
|  | 404bc284e0 | ||
|  | 9dee30ff0e | ||
|  | f91aadbea8 | ||
|  | aa15a10c91 | ||
|  | 5b03e36351 | ||
|  | b9ba9ffad2 | ||
|  | 642be5d16c | ||
|  | ee68d715bf | ||
|  | 224084f056 | ||
|  | 1cd8c849b8 | ||
|  | 169f68bfcd | ||
|  | d2b7cfa2d1 | ||
|  | a40c7dff5d | ||
|  | e8e00630d3 | ||
|  | e33720c854 | ||
|  | bd8a4e0d17 | ||
|  | 586a2aef76 | ||
|  | ce1d8f6754 | ||
|  | 7b0f401065 | ||
|  | 8387016eef | ||
|  | 4e1342b641 | ||
|  | e45a184d90 | ||
|  | 979e1012d2 | ||
|  | fe10a50e23 | ||
|  | 8ab6d72519 | ||
|  | 3aada6dd1d | ||
|  | 0933036366 | ||
|  | 05f5abdc06 | ||
|  | fb875e0709 | ||
|  | 9acdc2f6bf | ||
|  | 028ce4bff6 | ||
|  | 3f245ad6db | ||
|  | 23115f4116 | ||
|  | cf5f48e6cc | ||
|  | 997fa756ad | ||
|  | e23f75b1cc | ||
|  | 6531e88761 | ||
|  | e76a9c2618 | ||
|  | 45be8a836b | ||
|  | 954b6032e7 | ||
|  | bd95416f27 | ||
|  | df2577ace2 | ||
|  | 720e6558c9 | ||
|  | c239f15d8a | ||
|  | dfa1f80a57 | ||
|  | 15dfb93b17 | ||
|  | 0ec8488c2b | ||
|  | 94b2e29cb1 | ||
|  | fefa8e9b4d | ||
|  | 32c4c44812 | ||
|  | 05195e2b1d | ||
|  | 4c2ff675b8 | ||
|  | e5692a4721 | ||
|  | 312e6a0d31 | ||
|  | 5bb8efa41f | ||
|  | 949a835f4a | ||
|  | 85e6042941 | ||
|  | 3cd2f28975 | ||
|  | 2179a72c3a | ||
|  | a5f282f156 | ||
|  | 40e8631f63 | ||
|  | 9ded05bb97 | ||
|  | ec8efa35a1 | ||
|  | f72bf20482 | ||
|  | ebde2002e8 | ||
|  | 352a66f46f | ||
|  | d84c5391f7 | ||
|  | f4c582472b | ||
|  | 1485586f7e | ||
|  | d5c9024335 | ||
|  | 860cf80703 | ||
|  | 897ff3161f | ||
|  | b356b2e501 | ||
|  | 1d2733c893 | ||
|  | 32d9126094 | ||
|  | db43314e50 | ||
|  | 68d2baeb65 | ||
|  | 1fd5f562d3 | ||
|  | 48e02f2086 | ||
|  | eab7b2b581 | ||
|  | 45abade7fc | ||
|  | 5372fc4b43 | ||
|  | 4e2f240c98 | ||
|  | bb3605518d | ||
|  | 3ef6d37f27 | ||
|  | 88e9f2f7f4 | ||
|  | 704a447df9 | ||
|  | a5fcb26a33 | ||
|  | 2491a61481 | ||
|  | 91831d51ed | ||
|  | 174f0c19f7 | ||
|  | de6fadfb4f | ||
|  | f946db3e00 | ||
|  | 8d05e5bc31 | ||
|  | cfb46820e4 | ||
|  | 081f1cbcc2 | ||
|  | 7bc6da326f | ||
|  | cd95a0df7b | ||
|  | 82fa497c16 | ||
|  | 44fd345206 | ||
|  | 088e1c9db4 | ||
|  | d4f16e666e | ||
|  | 8233cfd371 | ||
|  | ff05e2e30d | ||
|  | a8ea7dd3fb | ||
|  | 96f70a5303 | ||
|  | f1604c3e69 | ||
|  | c42c8c5192 | ||
|  | 5facb53a41 | ||
|  | d039ce89af | ||
|  | bc7605103f | ||
|  | d305d655d4 | ||
|  | 4ef1220b16 | ||
|  | a4fef143cd | ||
|  | 74ecb724a9 | ||
|  | af235897ab | ||
|  | 5ec4e458b5 | ||
|  | 2dae63ce21 | ||
|  | be748fe33b | ||
|  | 7408340b6a | ||
|  | 29eb92446e | ||
|  | ae6918742e | ||
|  | 863484bb65 | ||
|  | 1cd7ebce4c | ||
|  | eef8c7862e | ||
|  | b52375d446 | ||
|  | 6e2babc2ce | ||
|  | 08e253bed1 | ||
|  | c6661477a2 | ||
|  | 415cfd99a0 | ||
|  | 8c2e37381a | ||
|  | 45df79feba | ||
|  | 5824f992b7 | ||
|  | b0b60fafd5 | ||
|  | 8d98b02ba2 | ||
|  | a93fe79bc4 | ||
|  | 4aebd7be37 | ||
|  | 3170a5db32 | ||
|  | 3605b9eef6 | ||
|  | a945f1fde2 | ||
|  | 461a997b5b | ||
|  | a80afd7b4e | ||
|  | aad2b51d85 | ||
|  | 36a9a81ff1 | ||
|  | 42c88546ae | ||
|  | 0f0e86ef9b | ||
|  | 98efd9a857 | ||
|  | a0c27d95b7 | ||
|  | 984651d99d | ||
|  | c6f7370b30 | ||
|  | 3e4b8e8985 | ||
|  | 73f08b98d2 | ||
|  | 8607a74206 | ||
|  | 8339f3ceb3 | ||
|  | c0c9f3cc19 | ||
|  | 81f4813c29 | ||
|  | 94f57745b9 | ||
|  | 54fb2ebbe0 | ||
|  | 02d122b65b | ||
|  | df0a5561a1 | ||
|  | f7c55da7d0 | ||
|  | b385f701ce | ||
|  | 05dd42f443 | ||
|  | 36d816d5cb | ||
|  | 92a6746e70 | ||
|  | 1728848a39 | ||
|  | f9eb4e7487 | ||
|  | d0b9f33aeb | ||
|  | 718583b241 | ||
|  | 6737127e9a | ||
|  | 19a7b4479b | ||
|  | c340647502 | ||
|  | 0f987d2982 | ||
|  | 52bcaed169 | ||
|  | 177bd565ac | ||
|  | c801c32fc5 | ||
|  | d090cf3058 | ||
|  | 1e4b82cc94 | ||
|  | 3426f31184 | ||
|  | b4fb7af1df | ||
|  | b36647598b | ||
|  | fd6b94f20e | ||
|  | 296dc0ed8a | ||
|  | 4f869e14d6 | ||
|  | 5704270e9d | ||
|  | 505b381e85 | ||
|  | da6cb15393 | ||
|  | 16843f6cc8 | ||
|  | 64f3ad1fd4 | ||
|  | ff4c4f99b3 | ||
|  | f5d2e09569 | ||
|  | f2bdbe0d4d | ||
|  | c51a13caa6 | ||
|  | 7840c78a23 | ||
|  | c706f3246b | ||
|  | 608eedf88d | ||
|  | a564ca82be | ||
|  | c868b1fee2 | ||
|  | 22374f718f | ||
|  | abe3cfcf41 | ||
|  | 59db4b50cd | ||
|  | bdae38765d | ||
|  | 66d3ceeb61 | ||
|  | 445dd17db3 | ||
|  | cff78a2577 | ||
|  | 6a09e64195 | ||
|  | 22eabe5eab | ||
|  | b69ba36c2d | ||
|  | 5240aad22b | ||
|  | 2897eb3cb3 | ||
|  | d3f2f00c25 | ||
|  | bacfb913a0 | ||
|  | c99d0236a0 | ||
|  | aac2b655f7 | ||
|  | 126c41e73a | ||
|  | 359ee54f0d | ||
|  | 28ab560907 | ||
|  | ead252fee4 | ||
|  | abf67914c4 | ||
|  | 127884e9dd | ||
|  | 654f5049eb | ||
|  | 979ca34259 | ||
|  | 4dd1086805 | ||
|  | 3503d4b72c | ||
|  | b8d32a0d33 | ||
|  | 45dca55fc8 | ||
|  | 445d8ecd9f | ||
|  | c980add503 | ||
|  | 133842392a | ||
|  | 8baf2ef155 | ||
|  | 20b71340bc | ||
|  | 61d8baf8b1 | ||
|  | 56a9645aa5 | ||
|  | 85877000a6 | ||
|  | 2f7d2477b6 | ||
|  | 21ea3f05f4 | ||
|  | 79d3492e90 | ||
|  | 5972777abe | ||
|  | 8e373ff868 | ||
|  | a4db92da3a | ||
|  | 9b777eb281 | ||
|  | bd3c652184 | ||
|  | 800f747570 | ||
|  | 2b8423437e | ||
|  | 8b4b6945f8 | ||
|  | e5ecfec5c4 | ||
|  | f95dbff71f | ||
|  | 098f6830a6 | ||
|  | d1ecebdb52 | ||
|  | 590b654251 | ||
|  | 3bf190c8ab | ||
|  | dcca7638e0 | ||
|  | 70e45ad37b | ||
|  | db88210289 | ||
|  | d2e0d96cc3 | ||
|  | 3feba82ccc | ||
|  | db924da231 | ||
|  | fc55ae7e6d | ||
|  | 86e757a6ad | ||
|  | 4790715cd3 | ||
|  | e7e9c60042 | ||
|  | 1c3bc52cc4 | ||
|  | 5227dff0e1 | ||
|  | 33f0b5b7c2 | ||
|  | 0a02968303 | ||
|  | f7bf658c07 | ||
|  | 8d16a0abad | ||
|  | c974b97ca3 | ||
|  | b8025bfebd | ||
|  | 30323b253f | ||
|  | 535c3ede96 | ||
|  | 89fed8ca33 | ||
|  | f43c77aaed | ||
|  | 96c676b371 | ||
|  | 113047e1a2 | ||
|  | abed57cb53 | ||
|  | c01a800a6b | ||
|  | d648832a2d | ||
|  | f06833fbd2 | ||
|  | c561addc94 | ||
|  | 702f5f1f4c | ||
|  | 1273f179e8 | ||
|  | 5d02f60bde | ||
|  | 4cf7a108e8 | ||
|  | 42635c3938 | ||
|  | ed43dc842b | ||
|  | 49d4db6cd2 | ||
|  | ea80ab2cae | ||
|  | 382e808b8d | ||
|  | 846befa7e0 | ||
|  | 74dd29f843 | ||
|  | b0473bffcb | ||
|  | 24dd9ab1a7 | ||
|  | 49d3037e87 | ||
|  | 37ad2bd4e8 | ||
|  | 7d7b332b02 | ||
|  | ac033b8612 | ||
|  | a7b98dfe25 | ||
|  | 7fb7c86c46 | ||
|  | ed036598a9 | ||
|  | 160bb70cdf | ||
|  | c2e61f3c21 | ||
|  | 18218467f3 | ||
|  | 17e298ad2a | ||
|  | d031a374f9 | ||
|  | 55f69c98cb | ||
|  | 71f2e4306d | ||
|  | f8af23a025 | ||
|  | 4ef55a6cd3 | ||
|  | 312f866723 | ||
|  | 0ebe1f6dec | ||
|  | 2ad92e0e6e | ||
|  | ac8823cdcf | ||
|  | 77565f7ee4 | ||
|  | d656d90fa8 | ||
|  | 175b3b0834 | ||
|  | 7477e6b714 | ||
|  | cd6568db69 | ||
|  | 6aff325fb2 | ||
|  | 0d603cfe9c | ||
|  | 34a1f14a17 | ||
|  | efe1c8a070 | ||
|  | 1575844344 | ||
|  | 221ac1c208 | ||
|  | 57442db759 | ||
|  | 5fdb3e7cd6 | ||
|  | 96f259726c | ||
|  | 4936efba5e | ||
|  | d5a3559a2f | ||
|  | 114a1c7f52 | ||
|  | ce5265c203 | ||
|  | 1a575d926f | ||
|  | 85c818a39e | ||
|  | 4ffa2defe4 | ||
|  | 8825157fbb | ||
|  | 966d608dc5 | ||
|  | b808c89471 | ||
|  | 75d4e6490f | ||
|  | a82775f544 | ||
|  | 6a22ad0171 | ||
|  | c854e88186 | ||
|  | d02203060c | ||
|  | cf703b0433 | ||
|  | c0197a72d3 | ||
|  | e5a543e283 | ||
|  | b8b029b7d3 | ||
|  | 370f368b1a | ||
|  | 8288b45b4f | ||
|  | fe529faf8e | ||
|  | ab931b177d | ||
|  | 9aa3465513 | ||
|  | 6c70fc1a6c | ||
|  | 1ccc39962a | ||
|  | 99c941fc85 | ||
|  | 19729fdcc2 | ||
|  | 02e17998ce | ||
|  | 459e00c67a | ||
|  | 292f665650 | ||
|  | 93bbb79569 | ||
|  | 273e724f2b | ||
|  | 5d2615c56f | ||
|  | bfaaf21330 | ||
|  | dcb8415b7a | ||
|  | 699e1c75ce | ||
|  | 465b6e613e | ||
|  | 05fa105855 | ||
|  | d7a0cdebe5 | ||
|  | b049ab31eb | ||
|  | 6db4dcff7a | ||
|  | 3eeaef00ec | ||
|  | 8bf4c38a00 | ||
|  | 3a32b09ad1 | ||
|  | 6315982752 | ||
|  | 374a171e82 | ||
|  | fc5d801f91 | ||
|  | 5146641848 | ||
|  | cdd0ac42cf | ||
|  | e5895500a2 | ||
|  | 9cb4dde3fa | ||
|  | 3c2a4370a5 | ||
|  | e7a360dd6f | ||
|  | c814c2fd35 | ||
|  | fefa7fe262 | ||
|  | 26f01a29d1 | ||
|  | 169d4090ab | ||
|  | 0b43754d60 | ||
|  | 8b3b26b813 | ||
|  | 5426af4f81 | ||
|  | 4e2c3a579d | ||
|  | 5ae2693241 | ||
|  | 41c86b0d19 | ||
|  | 40788e8c3d | ||
|  | 0d29120033 | ||
|  | 4be598f865 | ||
|  | 558a6d509e | ||
|  | 75cd02aad2 | ||
|  | e4c4451482 | ||
|  | 0671632477 | ||
|  | 54c230c264 | ||
|  | 64ba878eda | ||
|  | 01acd6dd76 | ||
|  | 9d819b52d3 | ||
|  | 37bac5cdc9 | ||
|  | 78c718c591 | ||
|  | 284b8bf6ca | ||
|  | 5a5084b837 | ||
|  | 3b8058e1f1 | ||
|  | 2a3168e0d6 | ||
|  | a8ac6e4a15 | ||
|  | 6172cf9fba | ||
|  | b728ec3909 | ||
|  | 61a53bbcff | ||
|  | 17d13dd084 | ||
|  | edcb28d591 | ||
|  | ad101119a7 | ||
|  | bc36676d31 | ||
|  | d76fe120ab | ||
|  | 2e95949b80 | ||
|  | ae14d85e24 | ||
|  | fad6304c60 | ||
|  | a4dd3c8ce9 | ||
|  | 6d1a5d45e2 | ||
|  | a6c7043e03 | ||
|  | bcc400dafa | ||
|  | 8fbedf3441 | ||
|  | 2e8a9c9874 | ||
|  | 44fc41b3e5 | ||
|  | 7212c20a1b | ||
|  | 7ff142de1c | ||
|  | e67efb199d | ||
|  | 20128bd04b | ||
|  | c0fefdde28 | ||
|  | f6ee160e66 | ||
|  | 06acc2004f | ||
|  | 43ac2ce4c8 | ||
|  | b32bf72b5f | ||
|  | c6880c957e | ||
|  | 095b71ed96 | ||
|  | 9160e496bc | ||
|  | 2a7ac78f02 | ||
|  | 64efa4627d | ||
|  | f7e35569ce | ||
|  | e8af32ec2b | ||
|  | e092ce51f6 | ||
|  | 7b78edb1b7 | ||
|  | b332e7090e | ||
|  | 67eb7723d6 | ||
|  | 251d138474 | ||
|  | 1170dfac05 | ||
|  | 4157f141c7 | ||
|  | f569abd28a | ||
|  | 088f9687c0 | ||
|  | e23df1f07a | ||
|  | c818540dfd | ||
|  | 21365cbe1a | ||
|  | 5471a80a96 | ||
|  | d7b6fa9cd0 | ||
|  | dfdc2e02ef | ||
|  | 893ec9a302 | ||
|  | 05f65c38e6 | ||
|  | 2e9d062ec0 | ||
|  | 6b0b394e61 | ||
|  | 25621396c9 | ||
|  | 82aa0271f3 | ||
|  | 653cab13f8 | ||
|  | b526f86b49 | ||
|  | 53c0f00888 | ||
|  | f0c4d9de40 | ||
|  | 03ef8cec83 | ||
|  | 85f2a2e8c2 | ||
|  | 584b3e6642 | ||
|  | 39b7ef841d | ||
|  | aa16a9098d | ||
|  | 7b8c2707bc | ||
|  | 60e26a31a7 | ||
|  | 3473c25c14 | ||
|  | e52f022026 | ||
|  | b1a7df8e43 | ||
|  | 0fd2479b7c | ||
|  | 273857f914 | ||
|  | a08b85dbc8 | ||
|  | a0aedf299a | ||
|  | 3c61426844 | ||
|  | 786f228076 | ||
|  | 004da28792 | ||
|  | 6e2be6efb6 | ||
|  | a994dfcfbc | ||
|  | 7a8ea2ac93 | ||
|  | 0da3965d19 | ||
|  | 885fd7bb46 | ||
|  | 08771f9c89 | ||
|  | 8be48195a5 | ||
|  | 98ce2d650e | ||
|  | 3af327116a | ||
|  | b75434db93 | ||
|  | 04e912aacd | ||
|  | d7be352f87 | ||
|  | 96be3ec22c | ||
|  | 32e7e0d790 | ||
|  | becc320e62 | ||
|  | 7666ed57d1 | ||
|  | 5e61d0955e | ||
|  | e8a4662ae7 | ||
|  | a48da3bd3b | ||
|  | 5f1a5d7b99 | ||
|  | 3e28a9db8f | ||
|  | ebf6071d77 | ||
|  | 47a35fb9fb | ||
|  | 48e88aba44 | ||
|  | b85f99c140 | ||
|  | 0a5e0e1f71 | ||
|  | 85dc22ebb7 | ||
|  | 5c21526009 | ||
|  | 14dff1cefc | ||
|  | 39fbb844f9 | ||
|  | ca4e0c973a | ||
|  | ecb42bee80 | ||
|  | 674ed2a9f3 | ||
|  | 252daf9717 | ||
|  | 196b8eaad3 | ||
|  | 8e526ba1bf | ||
|  | 19225828d9 | ||
|  | 7e594126be | ||
|  | d2529e6334 | ||
|  | 97344f18e2 | ||
|  | 33934db629 | ||
|  | 6c6165c9f5 | ||
|  | 853460b20d | ||
|  | cc4d9676c5 | ||
|  | 1cf1b819f4 | ||
|  | f916c66d2b | ||
|  | 550aa86b45 | ||
|  | 014e764758 | ||
|  | d1fc28432b | ||
|  | 879576f0a2 | ||
|  | 69098210be | ||
|  | 99df4f892d | ||
|  | 7bc04fbad3 | ||
|  | 8a74ce578d | ||
|  | 0805e4e5de | ||
|  | f1060fc88e | ||
|  | 7d3d3d0a3a | ||
|  | 40377032e3 | ||
|  | b2971edd7d | ||
|  | c37d723692 | ||
|  | 30f9026e1d | ||
|  | 332286072e | ||
|  | d6da172a2a | ||
|  | ebfe584afc | ||
|  | 6250023583 | ||
|  | 6b4f3d63b8 | ||
|  | 56db773a09 | ||
|  | fc6c472401 | ||
|  | 2cd42a6866 | ||
|  | 36a90c345c | ||
|  | ef1e82c72c | ||
|  | 88f9534685 | ||
|  | 68254a052a | ||
|  | 2425b3a166 | ||
|  | 5524ed753b | ||
|  | 89711723da | ||
|  | bed2740ffd | ||
|  | 751d633c3d | ||
|  | 45952cbdf2 | ||
|  | b355dd7b23 | ||
|  | 48a186f172 | ||
|  | 39dc7ec2ab | ||
|  | 2fedabd3b9 | ||
|  | 6d719e9480 | ||
|  | 05e278afda | ||
|  | 87dbf462cb | ||
|  | 40e896bc5b | ||
|  | 3e940f80c7 | ||
|  | dbf2888d43 | ||
|  | d412355324 | ||
|  | 178732217f | ||
|  | de17b95c3d | ||
|  | d14e774525 | ||
|  | ca5402a7fa | ||
|  | 7a6fa7c5b4 | ||
|  | da36c286a6 | ||
|  | d3901bcf2e | ||
|  | 94c8d4fdfb | ||
|  | ab8bdc18bb | ||
|  | c9dcd7442a | ||
|  | 34c8f13346 | ||
|  | 7a8ccda95c | ||
|  | 44a1448542 | ||
|  | c87d89ffaf | ||
|  | 0868749d42 | ||
|  | 1d40ee23f0 | ||
|  | 8893f32603 | ||
|  | adcf7e8dc3 | ||
|  | 901f7c5c36 | ||
|  | 775bb413b3 | ||
|  | 64cd5b5a46 | ||
|  | ae356609b1 | ||
|  | 6102a5d2b0 | ||
|  | f8782ee2d7 | ||
|  | 6181ec4c77 | ||
|  | e0e7a685ef | ||
|  | ae1f8cdad2 | ||
|  | a4cf792e6d | ||
|  | 89109ded53 | ||
|  | e20e52a4b2 | ||
|  | 20c4b1cbec | ||
|  | 5238b0241d | ||
|  | 9cdf6c203d | ||
|  | 839335cae6 | ||
|  | a99b2ce167 | ||
|  | b695141d87 | ||
|  | 92d5c9f866 | ||
|  | 7f18a1ffe0 | ||
|  | 8c3fdaaa62 | ||
|  | 5ac1c69710 | ||
|  | de2d5fba63 | ||
|  | 33d516748f | ||
|  | de17f6f0fd | ||
|  | 756731fc02 | ||
|  | e46be0415f | ||
|  | aa02fb50bf | ||
|  | 8b6cd9c772 | ||
|  | cdd0d3351a | ||
|  | 8b6d584529 | ||
|  | f49fdd4141 | ||
|  | b26e1be81a | ||
|  | bacab38d7f | ||
|  | 701c05ce96 | ||
|  | 438c452585 | ||
|  | 0a7a1eff3f | ||
|  | 87e743e381 | ||
|  | a03f1b3d55 | ||
|  | 2d8dc3d243 | ||
|  | b982232cc5 | ||
|  | 61c8d728ac | ||
|  | 851a2bf855 | ||
|  | e0bdde3630 | ||
|  | 6a0dcd7f0e | ||
|  | 75f0b4c879 | ||
|  | db536a9504 | ||
|  | 0fb114dede | ||
|  | e703342179 | ||
|  | 35c8f4a611 | ||
|  | 7c89ae44a9 | ||
|  | 84fe06da22 | ||
|  | 806318c8b3 | ||
|  | 3aac2e1822 | ||
|  | 168baef433 | ||
|  | 6dba6cd78d | ||
|  | 502250d08f | ||
|  | 7395f0e680 | ||
|  | 494d3fdaca | ||
|  | 7b86a157de | ||
|  | 0988c41785 | ||
|  | 522db1bf01 | ||
|  | 06f066f90d | ||
|  | f37b20677b | ||
|  | cd2eac1032 | ||
|  | 8ac38d58d7 | ||
|  | 4c80cc313a | ||
|  | 1c65fee9b4 | ||
|  | 90dda7edc1 | ||
|  | da054fae20 | ||
|  | bdb6611e30 | ||
|  | 9284f973f1 | ||
|  | 2bfd64c3c9 | ||
|  | 939d24cce5 | ||
|  | 27b0183c46 | ||
|  | d14efacac7 | ||
|  | 150a002c40 | ||
|  | ce0def3bd8 | ||
|  | ee20fa97c2 | ||
|  | 7403b7d700 | ||
|  | 87ef173e0a | ||
|  | 52a3fb6bc7 | ||
|  | 92e2a257a6 | ||
|  | 32e175752c | ||
|  | d43f7180dc | ||
|  | 0129c2b0fc | ||
|  | 4ed1990001 | ||
|  | 5bd6ab27ae | ||
|  | f3593b89fa | ||
|  | 23d84b2310 | ||
|  | fdc49402ec | ||
|  | 5457c133e1 | ||
|  | 292e588ee3 | ||
|  | 243494c25e | ||
|  | e4365f3706 | ||
|  | 310f3038d3 | ||
|  | 4e6033273d | ||
|  | 73718586d3 | ||
|  | 011abe61e8 | ||
|  | fe3a37f89d | ||
|  | 8aea44e77b | ||
|  | 5529aec0d6 | ||
|  | 369549d23f | ||
|  | 181ea9a381 | ||
|  | 76b8f2854e | ||
|  | 320e5198f9 | ||
|  | e522539e2d | ||
|  | 7c996b83d2 | ||
|  | 3dd354d7aa | ||
|  | f4ad6e2157 | ||
|  | 8b170dc2bf | ||
|  | dcb9d779bf | ||
|  | 80f736d670 | ||
|  | 8502c6da3c | ||
|  | b131449422 | ||
|  | 6eebc4a620 | ||
|  | 4661ab1179 | ||
|  | 86046445ed | ||
|  | baea9bf944 | ||
|  | 0951ee9e63 | ||
|  | 5492528287 | ||
|  | 14dbd220c2 | ||
|  | babc890c59 | ||
|  | 6f7b47ff40 | ||
|  | 3991f03202 | ||
|  | 27271d5da7 | ||
|  | 627312e1de | ||
|  | bfc9550e4e | ||
|  | 2b9c21268b | ||
|  | 3dce4ed6f1 | ||
|  | 0f16c2ea87 | ||
|  | 9a635f0686 | ||
|  | 6a0d4b2baa | ||
|  | ac017098ad | ||
|  | 98fef2640d | ||
|  | 8bb66e133a | ||
|  | 68a582901d | ||
|  | c094f4c06e | ||
|  | f7ca545544 | ||
|  | 69b4716894 | ||
|  | 7e44dcc5bf | ||
|  | ab9843e183 | ||
|  | 01af706ade | ||
|  | 9ebdb08e99 | ||
|  | a74ffe25d9 | ||
|  | 7f95e27707 | ||
|  | 1facf5bba3 | ||
|  | 03d77009eb | ||
|  | 8afd6812b5 | ||
|  | ec9ad78fcf | ||
|  | 6f4e93dc90 | ||
|  | a38e43862d | ||
|  | 39294bb037 | ||
|  | edc5e59b78 | ||
|  | c00fd9fd37 | ||
|  | b3e621dd9f | ||
|  | 6e8c49b978 | ||
|  | 398d57133d | ||
|  | 16521a6feb | ||
|  | 3ca0b37a3e | ||
|  | cf2ec1229d | ||
|  | fe9b1e5f9b | ||
|  | f5b96ddf01 | ||
|  | 2fe076fb27 | ||
|  | 99249cff04 | ||
|  | 0cdf7b0613 | ||
|  | 90bcf4f157 | ||
|  | 03c3ec4e12 | ||
|  | ca9bb20d64 | ||
|  | c6bc078fd9 | ||
|  | 2f4bd6e52c | ||
|  | 2affe53727 | ||
|  | 09654d7dd8 | ||
|  | 90a4e37815 | ||
|  | 60889c0c79 | ||
|  | 20f3408d96 | ||
|  | e9d86789db | ||
|  | 5152b7c66c | ||
|  | c494c4e12c | ||
|  | 54d58ccb7e | ||
|  | 714a77bfbe | ||
|  | d48f8bf5cc | ||
|  | 99d97754a6 | ||
|  | b9d437de2a | ||
|  | 11403f2019 | ||
|  | 1ca102d639 | ||
|  | 339ba55111 | ||
|  | 14ae59885a | ||
|  | e3ef54f99b | ||
|  | 001901f9a9 | ||
|  | 6a98f60e2e | ||
|  | 6f2e24c47d | ||
|  | aafa368923 | ||
|  | eb783cab4c | ||
|  | 6533aa865a | ||
|  | f1a1e1bc07 | ||
|  | 953f4838dd | ||
|  | 130b892d34 | ||
|  | 6ad525c77e | ||
|  | d0ca74ad27 | ||
|  | 9806f69b4d | ||
|  | 34d9b5e3d7 | ||
|  | 3bf5189d86 | ||
|  | 12e5b0681b | ||
|  | 8c0285d608 | ||
|  | 36558fa3b8 | ||
|  | 235f940cde | ||
|  | 803d61fcbc | ||
|  | ffbd7d8de4 | ||
|  | 4ed924d7c7 | ||
|  | 798dc9948b | ||
|  | 13515f7ee4 | ||
|  | ef80824c26 | ||
|  | c8503fd65e | ||
|  | b3c454fb1c | ||
|  | 1d7723e873 | ||
|  | 77100b2365 | ||
|  | 259a788134 | ||
|  | 39511455cb | ||
|  | b04c16178e | ||
|  | 49a959c06e | ||
|  | 096a8932b4 | ||
|  | e39e66df93 | ||
|  | 513633f49a | ||
|  | eb3740daaf | ||
|  | f7947b148a | ||
|  | 9a2a702f3f | ||
|  | c65d95bf29 | ||
|  | 753a5edc4f | ||
|  | 0b3f853c2d | ||
|  | 3527fcf1d5 | ||
|  | 4544a89c7a | ||
|  | ffeae9005e | ||
|  | 47217bcfb7 | ||
|  | 80ff58b57a | ||
|  | d15dd368f1 | ||
|  | 8a2ec32bd8 | ||
|  | 410496ed52 | ||
|  | b7b07552e5 | ||
|  | 44486e80d9 | ||
|  | 7890c527d8 | ||
|  | 2c82ab79a7 | ||
|  | e3ebe5fc53 | ||
|  | 0ac430892e | ||
|  | a7739c942c | ||
|  | 24581482d0 | ||
|  | 0571c3b453 | ||
|  | 73e7f5a0b0 | ||
|  | 20c0adb961 | ||
|  | a01e03562f | ||
|  | d184ed0130 | ||
|  | 089e1c2aee | ||
|  | ebab0e91ee | ||
|  | 858a2b1b88 | ||
|  | 02bd59827c | ||
|  | 4991428510 | ||
|  | 3b245f5dc1 | ||
|  | c9c81da901 | ||
|  | 4919cdc3fb | ||
|  | e90e1f577d | ||
|  | afd4284403 | ||
|  | 150b350d31 | ||
|  | 2818520bd1 | ||
|  | 2819952292 | ||
|  | 5af71af51c | ||
|  | 07a55b51df | ||
|  | 66dd68b49d | ||
|  | 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 | 
							
								
								
									
										340
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,340 @@ | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
| 		       Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 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. | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
|   The licenses for most software are designed to take away your | ||||
| freedom to share and change it.  By contrast, the GNU General Public | ||||
| License is intended to guarantee your freedom to share and change free | ||||
| software--to make sure the software is free for all its users.  This | ||||
| General Public License applies to most of the Free Software | ||||
| Foundation's software and to any other program whose authors commit to | ||||
| using it.  (Some other Free Software Foundation software is covered by | ||||
| the GNU Library General Public License instead.)  You can apply it to | ||||
| your programs, too. | ||||
|  | ||||
|   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 | ||||
| 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 software, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of such a program, whether | ||||
| gratis or for a fee, you must give the recipients all the rights that | ||||
| you have.  You must make sure that they, too, receive or can get the | ||||
| source code.  And you must show them these terms so they know their | ||||
| rights. | ||||
|  | ||||
|   We protect your rights with two steps: (1) copyright the software, and | ||||
| (2) offer you this license which gives you legal permission to copy, | ||||
| distribute and/or modify the software. | ||||
|  | ||||
|   Also, for each author's protection and ours, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| software.  If the software is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original, so | ||||
| that any problems introduced by others will not reflect on the original | ||||
| authors' reputations. | ||||
|  | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that redistributors of a free | ||||
| program will individually obtain patent licenses, in effect making the | ||||
| program proprietary.  To prevent this, we have made it clear that any | ||||
| patent must be licensed for everyone's free use or not licensed at all. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow. | ||||
|  | ||||
| 		    GNU GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License applies to any program or other work which contains | ||||
| a notice placed by the copyright holder saying it may be distributed | ||||
| under the terms of this General Public License.  The "Program", below, | ||||
| refers to any such program or work, and a "work based on the Program" | ||||
| means either the Program or any derivative work under copyright law: | ||||
| that is to say, a work containing the Program or a portion of it, | ||||
| either verbatim or with modifications and/or translated into another | ||||
| language.  (Hereinafter, translation is included without limitation in | ||||
| the term "modification".)  Each licensee is addressed as "you". | ||||
|  | ||||
| Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running the Program is not restricted, and the output from the Program | ||||
| is covered only if its contents constitute a work based on the | ||||
| Program (independent of having been made by running the Program). | ||||
| Whether that is true depends on what the Program does. | ||||
|  | ||||
|   1. You may copy and distribute verbatim copies of the Program's | ||||
| source code as you receive it, in any medium, provided that you | ||||
| conspicuously and appropriately publish on each copy an appropriate | ||||
| copyright notice and disclaimer of warranty; keep intact all the | ||||
| notices that refer to this License and to the absence of any warranty; | ||||
| and give any other recipients of the Program a copy of this License | ||||
| along with the Program. | ||||
|  | ||||
| You may charge a fee for the physical act of transferring a copy, and | ||||
| you may at your option offer warranty protection in exchange for a fee. | ||||
|  | ||||
|   2. You may modify your copy or copies of the Program or any portion | ||||
| of it, thus forming a work based on the Program, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) You must cause the modified files to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
|  | ||||
|     b) You must cause any work that you distribute or publish, that in | ||||
|     whole or in part contains or is derived from the Program or any | ||||
|     part thereof, to be licensed as a whole at no charge to all third | ||||
|     parties under the terms of this License. | ||||
|  | ||||
|     c) If the modified program normally reads commands interactively | ||||
|     when run, you must cause it, when started running for such | ||||
|     interactive use in the most ordinary way, to print or display an | ||||
|     announcement including an appropriate copyright notice and a | ||||
|     notice that there is no warranty (or else, saying that you provide | ||||
|     a warranty) and that users may redistribute the program under | ||||
|     these conditions, and telling the user how to view a copy of this | ||||
|     License.  (Exception: if the Program itself is interactive but | ||||
|     does not normally print such an announcement, your work based on | ||||
|     the Program is not required to print an announcement.) | ||||
|  | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Program, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Program, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote it. | ||||
|  | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Program. | ||||
|  | ||||
| In addition, mere aggregation of another work not based on the Program | ||||
| with the Program (or with a work based on the Program) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
|  | ||||
|   3. You may copy and distribute the Program (or a work based on it, | ||||
| under Section 2) in object code or executable form under the terms of | ||||
| Sections 1 and 2 above provided that you also do one of the following: | ||||
|  | ||||
|     a) Accompany it with the complete corresponding machine-readable | ||||
|     source code, which must be distributed under the terms of Sections | ||||
|     1 and 2 above on a medium customarily used for software interchange; or, | ||||
|  | ||||
|     b) Accompany it with a written offer, valid for at least three | ||||
|     years, to give any third party, for a charge no more than your | ||||
|     cost of physically performing source distribution, a complete | ||||
|     machine-readable copy of the corresponding source code, to be | ||||
|     distributed under the terms of Sections 1 and 2 above on a medium | ||||
|     customarily used for software interchange; or, | ||||
|  | ||||
|     c) Accompany it with the information you received as to the offer | ||||
|     to distribute corresponding source code.  (This alternative is | ||||
|     allowed only for noncommercial distribution and only if you | ||||
|     received the program in object code or executable form with such | ||||
|     an offer, in accord with Subsection b above.) | ||||
|  | ||||
| The source code for a work means the preferred form of the work for | ||||
| making modifications to it.  For an executable work, complete source | ||||
| code means all the source code for all modules it contains, plus any | ||||
| associated interface definition files, plus the scripts used to | ||||
| control compilation and installation of the executable.  However, as a | ||||
| special exception, 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. | ||||
|  | ||||
| If distribution of executable or object code is made by offering | ||||
| access to copy from a designated place, then offering equivalent | ||||
| access to copy the source code from the same place counts as | ||||
| distribution of the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
|  | ||||
|   4. You may not copy, modify, sublicense, or distribute the Program | ||||
| except as expressly provided under this License.  Any attempt | ||||
| otherwise to copy, modify, sublicense or distribute the Program is | ||||
| void, and will automatically terminate your rights under this License. | ||||
| However, parties who have received copies, or rights, from you under | ||||
| this License will not have their licenses terminated so long as such | ||||
| parties remain in full compliance. | ||||
|  | ||||
|   5. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Program or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Program (or any work based on the | ||||
| Program), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Program or works based on it. | ||||
|  | ||||
|   6. Each time you redistribute the Program (or any work based on the | ||||
| Program), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute or modify the Program 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 to | ||||
| this License. | ||||
|  | ||||
|   7. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Program at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Program by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Program. | ||||
|  | ||||
| If any portion of this section is held invalid or unenforceable under | ||||
| any particular circumstance, the balance of the section is intended to | ||||
| apply and the section as a whole is intended to apply in other | ||||
| circumstances. | ||||
|  | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system, which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
|  | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
|  | ||||
|   8. If the distribution and/or use of the Program is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Program under this License | ||||
| may add an explicit geographical distribution limitation excluding | ||||
| those countries, so that distribution is permitted only in or among | ||||
| countries not thus excluded.  In such case, this License incorporates | ||||
| the limitation as if written in the body of this License. | ||||
|  | ||||
|   9. The Free Software Foundation may publish revised and/or new versions | ||||
| of the 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. | ||||
|  | ||||
| Each version is given a distinguishing version number.  If the Program | ||||
| specifies a version number of this License which applies to it and "any | ||||
| later version", you have the option of following the terms and conditions | ||||
| either of that version or of any later version published by the Free | ||||
| Software Foundation.  If the Program does not specify a version number of | ||||
| this License, you may choose any version ever published by the Free Software | ||||
| Foundation. | ||||
|  | ||||
|   10. If you wish to incorporate parts of the Program into other free | ||||
| programs whose distribution conditions are different, write to the author | ||||
| to ask for permission.  For software which is copyrighted by the Free | ||||
| Software Foundation, write to the Free Software Foundation; we sometimes | ||||
| make exceptions for this.  Our decision will be guided by the two goals | ||||
| of preserving the free status of all derivatives of our free software and | ||||
| of promoting the sharing and reuse of software generally. | ||||
|  | ||||
| 			    NO WARRANTY | ||||
|  | ||||
|   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||||
| FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN | ||||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS | ||||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE | ||||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||||
| REPAIR OR CORRECTION. | ||||
|  | ||||
|   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||||
| YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||||
| PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGES. | ||||
|  | ||||
| 		     END OF TERMS AND CONDITIONS | ||||
|  | ||||
| 	    How to Apply These Terms to Your New Programs | ||||
|  | ||||
|   If you develop a new program, and you want it to be of the greatest | ||||
| possible use to the public, the best way to achieve this is to make it | ||||
| free software which everyone can redistribute and change under these terms. | ||||
|  | ||||
|   To do so, attach the following notices to the program.  It is safest | ||||
| to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least | ||||
| the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     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 | ||||
|  | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| If the program is interactive, make it output a short notice like this | ||||
| when it starts in an interactive mode: | ||||
|  | ||||
|     Gnomovision version 69, Copyright (C) year  name of author | ||||
|     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||
|     This is free software, and you are welcome to redistribute it | ||||
|     under certain conditions; type `show c' for details. | ||||
|  | ||||
| The hypothetical commands `show w' and `show c' should show the appropriate | ||||
| parts of the General Public License.  Of course, the commands you use may | ||||
| be called something other than `show w' and `show c'; they could even be | ||||
| mouse-clicks or menu items--whatever suits your program. | ||||
|  | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the program, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
|  | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||||
|   `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||||
|  | ||||
|   <signature of Ty Coon>, 1 April 1989 | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| This General Public License does not permit incorporating your program into | ||||
| proprietary programs.  If your program is a subroutine library, you may | ||||
| consider it more useful to permit linking proprietary applications with the | ||||
| library.  If this is what you want to do, use the GNU Library General | ||||
| Public License instead of this License. | ||||
							
								
								
									
										504
									
								
								COPYING.LIB
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										504
									
								
								COPYING.LIB
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,504 @@ | ||||
| 		  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 | ||||
|  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.] | ||||
|  | ||||
| 			    Preamble | ||||
|  | ||||
|   The licenses for most software are designed to take away your | ||||
| 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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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 | ||||
| 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 | ||||
| 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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   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. | ||||
|  | ||||
| 		  GNU LESSER 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". | ||||
|  | ||||
|   A "library" means a collection of software functions and/or data | ||||
| prepared so as to be conveniently linked with application programs | ||||
| (which use some of those functions and data) to form executables. | ||||
|  | ||||
|   The "Library", below, refers to any such software library or work | ||||
| which has been distributed under these terms.  A "work based on the | ||||
| Library" means either the Library or any derivative work under | ||||
| copyright law: that is to say, a work containing the Library or a | ||||
| portion of it, either verbatim or with modifications and/or translated | ||||
| straightforwardly into another language.  (Hereinafter, translation is | ||||
| included without limitation in the term "modification".) | ||||
|  | ||||
|   "Source code" for a work means the preferred form of the work for | ||||
| making modifications to it.  For a library, complete source code means | ||||
| all the source code for all modules it contains, plus any associated | ||||
| interface definition files, plus the scripts used to control compilation | ||||
| and installation of the library. | ||||
|  | ||||
|   Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running a program using the Library is not restricted, and output from | ||||
| such a program is covered only if its contents constitute a work based | ||||
| on the Library (independent of the use of the Library in a tool for | ||||
| writing it).  Whether that is true depends on what the Library does | ||||
| and what the program that uses the Library does. | ||||
|    | ||||
|   1. You may copy and distribute verbatim copies of the Library's | ||||
| complete source code as you receive it, in any medium, provided that | ||||
| you conspicuously and appropriately publish on each copy an | ||||
| appropriate copyright notice and disclaimer of warranty; keep intact | ||||
| all the notices that refer to this License and to the absence of any | ||||
| warranty; and distribute a copy of this License along with the | ||||
| Library. | ||||
|  | ||||
|   You may charge a fee for the physical act of transferring a copy, | ||||
| and you may at your option offer warranty protection in exchange for a | ||||
| fee. | ||||
|  | ||||
|   2. You may modify your copy or copies of the Library or any portion | ||||
| of it, thus forming a work based on the Library, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) The modified work must itself be a software library. | ||||
|  | ||||
|     b) You must cause the files modified to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
|  | ||||
|     c) You must cause the whole of the work to be licensed at no | ||||
|     charge to all third parties under the terms of this License. | ||||
|  | ||||
|     d) If a facility in the modified Library refers to a function or a | ||||
|     table of data to be supplied by an application program that uses | ||||
|     the facility, other than as an argument passed when the facility | ||||
|     is invoked, then you must make a good faith effort to ensure that, | ||||
|     in the event an application does not supply such function or | ||||
|     table, the facility still operates, and performs whatever part of | ||||
|     its purpose remains meaningful. | ||||
|  | ||||
|     (For example, a function in a library to compute square roots has | ||||
|     a purpose that is entirely well-defined independent of the | ||||
|     application.  Therefore, Subsection 2d requires that any | ||||
|     application-supplied function or table used by this function must | ||||
|     be optional: if the application does not supply it, the square | ||||
|     root function must still compute square roots.) | ||||
|  | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Library, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Library, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote | ||||
| it. | ||||
|  | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Library. | ||||
|  | ||||
| In addition, mere aggregation of another work not based on the Library | ||||
| with the Library (or with a work based on the Library) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
|  | ||||
|   3. You may opt to apply the terms of the ordinary GNU General Public | ||||
| License instead of this License to a given copy of the Library.  To do | ||||
| this, you must alter all the notices that refer to this License, so | ||||
| that they refer to the ordinary GNU General Public License, version 2, | ||||
| instead of to this License.  (If a newer version than version 2 of the | ||||
| ordinary GNU General Public License has appeared, then you can specify | ||||
| that version instead if you wish.)  Do not make any other change in | ||||
| these notices. | ||||
|  | ||||
|   Once this change is made in a given copy, it is irreversible for | ||||
| that copy, so the ordinary GNU General Public License applies to all | ||||
| subsequent copies and derivative works made from that copy. | ||||
|  | ||||
|   This option is useful when you wish to copy part of the code of | ||||
| the Library into a program that is not a library. | ||||
|  | ||||
|   4. You may copy and distribute the Library (or a portion or | ||||
| derivative of it, under Section 2) in object code or executable form | ||||
| under the terms of Sections 1 and 2 above provided that you accompany | ||||
| it with the complete corresponding machine-readable source code, which | ||||
| must be distributed under the terms of Sections 1 and 2 above on a | ||||
| medium customarily used for software interchange. | ||||
|  | ||||
|   If distribution of object code is made by offering access to copy | ||||
| from a designated place, then offering equivalent access to copy the | ||||
| source code from the same place satisfies the requirement to | ||||
| distribute the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
|  | ||||
|   5. A program that contains no derivative of any portion of the | ||||
| Library, but is designed to work with the Library by being compiled or | ||||
| linked with it, is called a "work that uses the Library".  Such a | ||||
| work, in isolation, is not a derivative work of the Library, and | ||||
| therefore falls outside the scope of this License. | ||||
|  | ||||
|   However, linking a "work that uses the Library" with the Library | ||||
| creates an executable that is a derivative of the Library (because it | ||||
| contains portions of the Library), rather than a "work that uses the | ||||
| library".  The executable is therefore covered by this License. | ||||
| Section 6 states terms for distribution of such executables. | ||||
|  | ||||
|   When a "work that uses the Library" uses material from a header file | ||||
| that is part of the Library, the object code for the work may be a | ||||
| derivative work of the Library even though the source code is not. | ||||
| Whether this is true is especially significant if the work can be | ||||
| linked without the Library, or if the work is itself a library.  The | ||||
| threshold for this to be true is not precisely defined by law. | ||||
|  | ||||
|   If such an object file uses only numerical parameters, data | ||||
| structure layouts and accessors, and small macros and small inline | ||||
| functions (ten lines or less in length), then the use of the object | ||||
| file is unrestricted, regardless of whether it is legally a derivative | ||||
| work.  (Executables containing this object code plus portions of the | ||||
| Library will still fall under Section 6.) | ||||
|  | ||||
|   Otherwise, if the work is a derivative of the Library, you may | ||||
| 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 | ||||
| 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 | ||||
| modification of the work for the customer's own use and reverse | ||||
| engineering for debugging such modifications. | ||||
|  | ||||
|   You must give prominent notice with each copy of the work that the | ||||
| Library is used in it and that the Library and its use are covered by | ||||
| this License.  You must supply a copy of this License.  If the work | ||||
| during execution displays copyright notices, you must include the | ||||
| copyright notice for the Library among them, as well as a reference | ||||
| directing the user to the copy of this License.  Also, you must do one | ||||
| of these things: | ||||
|  | ||||
|     a) Accompany the work with the complete corresponding | ||||
|     machine-readable source code for the Library including whatever | ||||
|     changes were used in the work (which must be distributed under | ||||
|     Sections 1 and 2 above); and, if the work is an executable linked | ||||
|     with the Library, with the complete machine-readable "work that | ||||
|     uses the Library", as object code and/or source code, so that the | ||||
|     user can modify the Library and then relink to produce a modified | ||||
|     executable containing the modified Library.  (It is understood | ||||
|     that the user who changes the contents of definitions files in the | ||||
|     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 | ||||
|     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 | ||||
|     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 | ||||
|     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 | ||||
| components (compiler, kernel, and so on) of the operating system on | ||||
| which the executable runs, unless that component itself accompanies | ||||
| the executable. | ||||
|  | ||||
|   It may happen that this requirement contradicts the license | ||||
| restrictions of other proprietary libraries that do not normally | ||||
| accompany the operating system.  Such a contradiction means you cannot | ||||
| use both them and the Library together in an executable that you | ||||
| distribute. | ||||
|  | ||||
|   7. You may place library facilities that are a work based on the | ||||
| Library side-by-side in a single library together with other library | ||||
| facilities not covered by this License, and distribute such a combined | ||||
| library, provided that the separate distribution of the work based on | ||||
| the Library and of the other library facilities is otherwise | ||||
| permitted, and provided that you do these two things: | ||||
|  | ||||
|     a) Accompany the combined library with a copy of the same work | ||||
|     based on the Library, uncombined with any other library | ||||
|     facilities.  This must be distributed under the terms of the | ||||
|     Sections above. | ||||
|  | ||||
|     b) Give prominent notice with the combined library of the fact | ||||
|     that part of it is a work based on the Library, and explaining | ||||
|     where to find the accompanying uncombined form of the same work. | ||||
|  | ||||
|   8. You may not copy, modify, sublicense, link with, or distribute | ||||
| the Library except as expressly provided under this License.  Any | ||||
| attempt otherwise to copy, modify, sublicense, link with, or | ||||
| distribute the Library is void, and will automatically terminate your | ||||
| rights under this License.  However, parties who have received copies, | ||||
| or rights, from you under this License will not have their licenses | ||||
| terminated so long as such parties remain in full compliance. | ||||
|  | ||||
|   9. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Library or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Library (or any work based on the | ||||
| Library), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Library or works based on it. | ||||
|  | ||||
|   10. Each time you redistribute the Library (or any work based on the | ||||
| 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 | ||||
| this License. | ||||
|  | ||||
|   11. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Library at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Library by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Library. | ||||
|  | ||||
| If any portion of this section is held invalid or unenforceable under any | ||||
| particular circumstance, the balance of the section is intended to apply, | ||||
| and the section as a whole is intended to apply in other circumstances. | ||||
|  | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
|  | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
|  | ||||
|   12. If the distribution and/or use of the Library is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Library under this License may add | ||||
| an explicit geographical distribution limitation excluding those countries, | ||||
| so that distribution is permitted only in or among countries not thus | ||||
| 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. | ||||
| Such new versions will be similar in spirit to the present version, | ||||
| but may differ in detail to address new problems or concerns. | ||||
|  | ||||
| Each version is given a distinguishing version number.  If the Library | ||||
| specifies a version number of this License which applies to it and | ||||
| "any later version", you have the option of following the terms and | ||||
| conditions either of that version or of any later version published by | ||||
| the Free Software Foundation.  If the Library does not specify a | ||||
| license version number, you may choose any version ever published by | ||||
| the Free Software Foundation. | ||||
|  | ||||
|   14. If you wish to incorporate parts of the Library into other free | ||||
| programs whose distribution conditions are incompatible with these, | ||||
| write to the author to ask for permission.  For software which is | ||||
| copyrighted by the Free Software Foundation, write to the Free | ||||
| Software Foundation; we sometimes make exceptions for this.  Our | ||||
| decision will be guided by the two goals of preserving the free status | ||||
| of all derivatives of our free software and of promoting the sharing | ||||
| and reuse of software generally. | ||||
|  | ||||
| 			    NO WARRANTY | ||||
|  | ||||
|   15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO | ||||
| WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. | ||||
| EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | ||||
| OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY | ||||
| KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||
| PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE | ||||
| LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME | ||||
| THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||||
|  | ||||
|   16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN | ||||
| WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY | ||||
| AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU | ||||
| FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR | ||||
| CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE | ||||
| LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | ||||
| RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | ||||
| FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | ||||
| SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | ||||
| DAMAGES. | ||||
|  | ||||
| 		     END OF TERMS AND CONDITIONS | ||||
|  | ||||
|            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 | ||||
| everyone can redistribute and change.  You can do so by permitting | ||||
| redistribution under these terms (or, alternatively, under the terms of the | ||||
| ordinary General Public License). | ||||
|  | ||||
|   To apply these terms, attach the following notices to the library.  It is | ||||
| safest to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least the | ||||
| "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the library's name and a brief idea of what it does.> | ||||
|     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 | ||||
|     License as published by the Free Software Foundation; either | ||||
|     version 2.1 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. | ||||
|  | ||||
|     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 | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the library, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
|  | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the | ||||
|   library `Frob' (a library for tweaking knobs) written by James Random Hacker. | ||||
|  | ||||
|   <signature of Ty Coon>, 1 April 1990 | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| That's all there is to it! | ||||
|  | ||||
|  | ||||
							
								
								
									
										31
									
								
								INSTALL
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								INSTALL
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| Installation | ||||
| ============ | ||||
|  | ||||
| 1) Generate custom makefiles. | ||||
|  | ||||
|    Run the 'configure' script from the top directory. | ||||
|  | ||||
|    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. | ||||
|  | ||||
|    Run 'make' from the top directory to build everything you configured. | ||||
|    Run 'make install' to build and install everything you configured. | ||||
|  | ||||
|    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. | ||||
|  | ||||
|    The tools will work fine without a configuration file being | ||||
|    present, but you ought to review the example file in doc/example.conf. | ||||
|  | ||||
| Please also refer to the WHATS_NEW file and the manual pages for the  | ||||
| individual commands. | ||||
|  | ||||
							
								
								
									
										156
									
								
								Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| # | ||||
| # Copyright (C) 2001-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 | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| SUBDIRS = doc include man scripts | ||||
|  | ||||
| ifeq ("@UDEV_RULES@", "yes") | ||||
|   SUBDIRS += udev | ||||
| endif | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
|   SUBDIRS += po | ||||
| endif | ||||
|  | ||||
| SUBDIRS += lib tools daemons libdm | ||||
|  | ||||
| ifeq ("@APPLIB@", "yes") | ||||
|   SUBDIRS += liblvm | ||||
| endif | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = doc include man scripts \ | ||||
|     lib tools daemons libdm \ | ||||
|     udev po liblvm test/api test | ||||
| endif | ||||
| DISTCLEAN_DIRS += lcov_reports* | ||||
| DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl | ||||
|  | ||||
| include make.tmpl | ||||
|  | ||||
| libdm: include | ||||
| lib: libdm | ||||
| liblvm: lib | ||||
| daemons: lib tools | ||||
| tools: lib device-mapper | ||||
| po: tools daemons | ||||
|  | ||||
| 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 | ||||
| device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper | ||||
|  | ||||
| ifeq ("@INTL@", "yes") | ||||
| lib.pofile: include.pofile | ||||
| tools.pofile: lib.pofile | ||||
| daemons.pofile: lib.pofile | ||||
| po.pofile: tools.pofile daemons.pofile | ||||
| pofile: po.pofile | ||||
| 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_cluster check_local: 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 | ||||
|  | ||||
| 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 $(top_srcdir)/$(basename $@) \ | ||||
| 		-d $(basename $@) -c -o - | $(SED) \ | ||||
| 		-e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \ | ||||
| 		-e "s/\(dmeventd_mirror.c\)/plugins\/mirror\/\1/" \ | ||||
| 		-e "s/\(dmeventd_snapshot.c\)/plugins\/snapshot\/\1/" \ | ||||
| 		>$@ | ||||
|  | ||||
| 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 | ||||
|  | ||||
| .PHONEY: unit-test ruby-test test-programs | ||||
|  | ||||
| # FIXME: put dependencies on libdm and liblvm | ||||
| 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 | ||||
							
								
								
									
										29
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README
									
									
									
									
									
								
							| @@ -1,2 +1,27 @@ | ||||
| This is pretty much empty so far...if you can't see subdirectories, | ||||
| try 'cvs -f update' | ||||
| This tree contains the LVM2 and device-mapper tools and libraries. | ||||
|  | ||||
| For more information about LVM2 read the changelog in 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/ | ||||
|  | ||||
| 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: | ||||
|   linux-lvm@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
|  | ||||
| Mailing list for LVM2 development, patches and commits: | ||||
|   lvm-devel@redhat.com | ||||
|   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm | ||||
|  | ||||
| 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 | ||||
|   | ||||
							
								
								
									
										1
									
								
								VERSION_DM
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								VERSION_DM
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| 1.02.62-cvs (2011-01-10) | ||||
							
								
								
									
										601
									
								
								WHATS_NEW_DM
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										601
									
								
								WHATS_NEW_DM
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,601 @@ | ||||
| Version 1.02.62 -  | ||||
| =================================== | ||||
|  | ||||
| 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 | ||||
| ============================= | ||||
|   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 | ||||
| ============================= | ||||
|   configure --with-owner= --with-group= to avoid -o and -g args to 'install' | ||||
|   Fix library selinux linking. | ||||
|  | ||||
| Version 1.00.16 - 16 Apr 2004 | ||||
| ============================= | ||||
|   Ignore error setting selinux file context if fs doesn't support it. | ||||
|  | ||||
| Version 1.00.15 - 7 Apr 2004 | ||||
| ============================ | ||||
|   Fix status overflow check in kernel patches. | ||||
|  | ||||
| Version 1.00.14 - 6 Apr 2004 | ||||
| ============================ | ||||
|   Fix static selinux build. | ||||
|  | ||||
| Version 1.00.13 - 6 Apr 2004 | ||||
| ============================ | ||||
|   Add some basic selinux support. | ||||
|  | ||||
| Version 1.00.12 - 6 Apr 2004 | ||||
| ============================ | ||||
|   Fix dmsetup.static install. | ||||
|  | ||||
| Version 1.00.11 - 5 Apr 2004 | ||||
| ============================ | ||||
|   configure --enable-static_link does static build in addition to dynamic. | ||||
|   Moved Makefile library targets definition into template. | ||||
|  | ||||
| Version 1.00.10 - 2 Apr 2004 | ||||
| ============================ | ||||
|   Fix DESTDIR handling. | ||||
|   Static build installs to dmsetup.static. | ||||
|   Basic support for internationalisation. | ||||
|   Minor Makefile tidy-ups/fixes. | ||||
|  | ||||
| Version 1.00.09 - 31 Mar 2004 | ||||
| ============================= | ||||
|   Update copyright notices to Red Hat. | ||||
|   Move full mknodes functionality from dmsetup into libdevmapper. | ||||
|   Avoid sscanf %as for uClibc compatibility. | ||||
|   Cope if DM_LIST_VERSIONS is not defined. | ||||
|   Add DM_LIST_VERSIONS functionality to kernel patches. | ||||
|   Generate new kernel patches for 2.4.26-rc1. | ||||
|  | ||||
| Version 1.00.08 - 27 Feb 2004 | ||||
| ============================= | ||||
|   Added 'dmsetup targets'. | ||||
|   Added event_nr support to 'dmsetup wait'. | ||||
|   Updated dmsetup man page. | ||||
|   Allow logging function to be reset to use internal one. | ||||
|   Bring log macros in line with LVM2 ones. | ||||
|   Added 'make install_static_lib' which installs libdevmapper.a. | ||||
|   Made configure/makefiles closer to LVM2 versions. | ||||
|   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. | ||||
							
								
								
									
										171
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| # generated automatically by aclocal 1.11.1 -*- Autoconf -*- | ||||
|  | ||||
| # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, | ||||
| # 2005, 2006, 2007, 2008, 2009  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. | ||||
|  | ||||
| # 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)?$]) | ||||
| 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`], | ||||
| 		     [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 "$2" 2>&1` | ||||
|         else  | ||||
| 	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$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]) | ||||
|         ]) | ||||
| 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/>.]) | ||||
|         ]) | ||||
| else | ||||
| 	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS | ||||
| 	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS | ||||
|         AC_MSG_RESULT([yes]) | ||||
| 	$3 | ||||
| fi[]dnl | ||||
| ])# PKG_CHECK_MODULES | ||||
|  | ||||
							
								
								
									
										1463
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1463
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										777
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										777
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,36 +1,62 @@ | ||||
| #!/bin/sh | ||||
| # | ||||
| # install - install a program, script, or datafile | ||||
| # This comes from X11R5 (mit/util/scripts/install.sh). | ||||
|  | ||||
| scriptversion=2006-10-14.15 | ||||
|  | ||||
| # This originates from X11R5 (mit/util/scripts/install.sh), which was | ||||
| # later released in X11R6 (xc/config/util/install.sh) with the | ||||
| # following copyright and license. | ||||
| # | ||||
| # Copyright 1991 by the Massachusetts Institute of Technology | ||||
| # Copyright (C) 1994 X Consortium | ||||
| # | ||||
| # Permission to use, copy, modify, distribute, and sell this software and its | ||||
| # documentation for any purpose is hereby granted without fee, provided that | ||||
| # the above copyright notice appear in all copies and that both that | ||||
| # copyright notice and this permission notice appear in supporting | ||||
| # documentation, and that the name of M.I.T. not be used in advertising or | ||||
| # publicity pertaining to distribution of the software without specific, | ||||
| # written prior permission.  M.I.T. makes no representations about the | ||||
| # suitability of this software for any purpose.  It is provided "as is" | ||||
| # without express or implied warranty. | ||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| # of this software and associated documentation files (the "Software"), to | ||||
| # deal in the Software without restriction, including without limitation the | ||||
| # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| # sell copies of the Software, and to permit persons to whom the Software is | ||||
| # furnished to do so, subject to the following conditions: | ||||
| # | ||||
| # The above copyright notice and this permission notice shall be included in | ||||
| # all copies or substantial portions of the Software. | ||||
| # | ||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE | ||||
| # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||||
| # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- | ||||
| # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| # | ||||
| # Except as contained in this notice, the name of the X Consortium shall not | ||||
| # be used in advertising or otherwise to promote the sale, use or other deal- | ||||
| # ings in this Software without prior written authorization from the X Consor- | ||||
| # tium. | ||||
| # | ||||
| # | ||||
| # FSF changes to this file are in the public domain. | ||||
| # | ||||
| # Calling this script install-sh is preferred over install.sh, to prevent | ||||
| # `make' implicit rules from creating a file called install from it | ||||
| # when there is no Makefile. | ||||
| # | ||||
| # This script is compatible with the BSD install script, but was written | ||||
| # from scratch.  It can only install one file at a time, a restriction | ||||
| # shared with many OS's install programs. | ||||
| # from scratch. | ||||
|  | ||||
| nl=' | ||||
| ' | ||||
| IFS=" ""	$nl" | ||||
|  | ||||
| # 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 paths if you don't have them in your path; or use env. vars. | ||||
| # Put in absolute file names if you don't have them in your path; | ||||
| # or use environment vars. | ||||
|  | ||||
| mvprog="${MVPROG-mv}" | ||||
| cpprog="${CPPROG-cp}" | ||||
| @@ -41,211 +67,441 @@ stripprog="${STRIPPROG-strip}" | ||||
| rmprog="${RMPROG-rm}" | ||||
| mkdirprog="${MKDIRPROG-mkdir}" | ||||
|  | ||||
| transformbasename="" | ||||
| transform_arg="" | ||||
| instcmd="$mvprog" | ||||
| chmodcmd="$chmodprog 0755" | ||||
| chowncmd="" | ||||
| chgrpcmd="" | ||||
| stripcmd="" | ||||
| posix_glob= | ||||
| posix_mkdir= | ||||
|  | ||||
| # Desired mode of installed file. | ||||
| mode=0755 | ||||
|  | ||||
| chmodcmd=$chmodprog | ||||
| chowncmd= | ||||
| chgrpcmd= | ||||
| stripcmd= | ||||
| rmcmd="$rmprog -f" | ||||
| mvcmd="$mvprog" | ||||
| src="" | ||||
| dst="" | ||||
| dir_arg="" | ||||
| src= | ||||
| dst= | ||||
| dir_arg= | ||||
| dstarg= | ||||
| no_target_directory= | ||||
|  | ||||
| while [ x"$1" != x ]; do | ||||
|     case $1 in | ||||
| 	-c) instcmd="$cpprog" | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE | ||||
|    or: $0 [OPTION]... SRCFILES... DIRECTORY | ||||
|    or: $0 [OPTION]... -t DIRECTORY SRCFILES... | ||||
|    or: $0 [OPTION]... -d DIRECTORIES... | ||||
|  | ||||
| 	-d) dir_arg=true | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| In the 1st form, copy SRCFILE to DSTFILE. | ||||
| In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. | ||||
| In the 4th, create DIRECTORIES. | ||||
|  | ||||
| 	-m) chmodcmd="$chmodprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| Options: | ||||
| -c         (ignored) | ||||
| -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. | ||||
| --help     display this help and exit. | ||||
| --version  display version info and exit. | ||||
|  | ||||
| 	-o) chowncmd="$chownprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| Environment variables override the default commands: | ||||
|   CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG | ||||
| " | ||||
|  | ||||
| 	-g) chgrpcmd="$chgrpprog $2" | ||||
| 	    shift | ||||
| 	    shift | ||||
| 	    continue;; | ||||
| while test $# -ne 0; do | ||||
|   case $1 in | ||||
|     -c) shift | ||||
|         continue;; | ||||
|  | ||||
| 	-s) stripcmd="$stripprog" | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     -d) dir_arg=true | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| 	-t=*) transformarg=`echo $1 | sed 's/-t=//'` | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     -g) chgrpcmd="$chgrpprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| 	-b=*) transformbasename=`echo $1 | sed 's/-b=//'` | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     --help) echo "$usage"; exit $?;; | ||||
|  | ||||
| 	*)  if [ x"$src" = x ] | ||||
| 	    then | ||||
| 		src=$1 | ||||
| 	    else | ||||
| 		# this colon is to work around a 386BSD /bin/sh bug | ||||
| 		: | ||||
| 		dst=$1 | ||||
| 	    fi | ||||
| 	    shift | ||||
| 	    continue;; | ||||
|     esac | ||||
| done | ||||
|     -m) mode=$2 | ||||
|         shift | ||||
|         shift | ||||
| 	case $mode in | ||||
| 	  *' '* | *'	'* | *' | ||||
| '*	  | *'*'* | *'?'* | *'['*) | ||||
| 	    echo "$0: invalid mode: $mode" >&2 | ||||
| 	    exit 1;; | ||||
| 	esac | ||||
|         continue;; | ||||
|  | ||||
| if [ x"$src" = x ] | ||||
| then | ||||
| 	echo "install:	no input file specified" | ||||
| 	exit 1 | ||||
| else | ||||
| 	true | ||||
| fi | ||||
|     -o) chowncmd="$chownprog $2" | ||||
|         shift | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| if [ x"$dir_arg" != x ]; then | ||||
| 	dst=$src | ||||
| 	src="" | ||||
| 	 | ||||
| 	if [ -d $dst ]; then | ||||
| 		instcmd=: | ||||
| 		chmodcmd="" | ||||
| 	else | ||||
| 		instcmd=mkdir | ||||
| 	fi | ||||
| else | ||||
|     -s) stripcmd=$stripprog | ||||
|         shift | ||||
|         continue;; | ||||
|  | ||||
| # 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 [ -f $src -o -d $src ] | ||||
| 	then | ||||
| 		true | ||||
| 	else | ||||
| 		echo "install:  $src does not exist" | ||||
| 		exit 1 | ||||
| 	fi | ||||
| 	 | ||||
| 	if [ x"$dst" = x ] | ||||
| 	then | ||||
| 		echo "install:	no destination specified" | ||||
| 		exit 1 | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|  | ||||
| # If destination is a directory, append the input filename; if your system | ||||
| # does not like double slashes in filenames, you may need to add some logic | ||||
|  | ||||
| 	if [ -d $dst ] | ||||
| 	then | ||||
| 		dst="$dst"/`basename $src` | ||||
| 	else | ||||
| 		true | ||||
| 	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 [ ! -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 [ $# -ne 0 ] ; do | ||||
| 	pathcomp="${pathcomp}${1}" | ||||
|     -t) dstarg=$2 | ||||
| 	shift | ||||
| 	shift | ||||
| 	continue;; | ||||
|  | ||||
| 	if [ ! -d "${pathcomp}" ] ; | ||||
|         then | ||||
| 		$mkdirprog "${pathcomp}" | ||||
| 	else | ||||
| 		true | ||||
| 	fi | ||||
|     -T) no_target_directory=true | ||||
| 	shift | ||||
| 	continue;; | ||||
|  | ||||
| 	pathcomp="${pathcomp}/" | ||||
|     --version) echo "$0 $scriptversion"; exit $?;; | ||||
|  | ||||
|     --)	shift | ||||
| 	break;; | ||||
|  | ||||
|     -*)	echo "$0: invalid option: $1" >&2 | ||||
| 	exit 1;; | ||||
|  | ||||
|     *)  break;; | ||||
|   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 | ||||
|   done | ||||
| fi | ||||
|  | ||||
| if [ x"$dir_arg" != x ] | ||||
| then | ||||
| 	$doit $instcmd $dst && | ||||
| 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 [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && | ||||
| 	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && | ||||
| 	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && | ||||
| 	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi | ||||
| else | ||||
| if test -z "$dir_arg"; then | ||||
|   trap '(exit $?); exit' 1 2 13 15 | ||||
|  | ||||
| # If we're going to rename the final executable, determine the name now. | ||||
|   # 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;; | ||||
|  | ||||
| 	if [ x"$transformarg" = x ]  | ||||
| 	then | ||||
| 		dstfile=`basename $dst` | ||||
|     *[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 | ||||
|  | ||||
| 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 | ||||
| 		dstfile=`basename $dst $transformbasename |  | ||||
| 			sed $transformarg`$transformbasename | ||||
| 	  mkdir_mode= | ||||
| 	fi | ||||
|  | ||||
| # don't allow the sed command to completely eliminate the filename | ||||
| 	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 [ x"$dstfile" = x ]  | ||||
| 	then | ||||
| 		dstfile=`basename $dst` | ||||
| 	    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 | ||||
| 		true | ||||
| 	  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 | ||||
|  | ||||
| # Make a temp file name in the proper directory. | ||||
|       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 | ||||
|  | ||||
| 	dsttmp=$dstdir/#inst.$$# | ||||
|   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 | ||||
|  | ||||
| # Move or copy the file name to the temp name | ||||
|     # Make a couple of temp file names in the proper directory. | ||||
|     dsttmp=$dstdir/_inst.$$_ | ||||
|     rmtmp=$dstdir/_rm.$$_ | ||||
|  | ||||
| 	$doit $instcmd $src $dsttmp && | ||||
|     # Trap to clean up those temp files at exit. | ||||
|     trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 | ||||
|  | ||||
| 	trap "rm -f ${dsttmp}" 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 | ||||
|     # 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"; } && | ||||
|  | ||||
| # 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. | ||||
|     # Now rename the file to the real destination. | ||||
|     { $doit $mvcmd -f "$dsttmp" "$dst" 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. | ||||
|  | ||||
| 	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && | ||||
| 	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && | ||||
| 	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && | ||||
| 	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;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. | ||||
| 	   # Now rename the file to the real destination. | ||||
| 	   $doit $mvcmd "$dsttmp" "$dst" | ||||
| 	 } | ||||
|     } || exit 1 | ||||
|  | ||||
| 	$doit $rmcmd -f $dstdir/$dstfile && | ||||
| 	$doit $mvcmd $dsttmp $dstdir/$dstfile  | ||||
|     trap '' 0 | ||||
|   fi | ||||
| done | ||||
|  | ||||
| fi && | ||||
|  | ||||
|  | ||||
| exit 0 | ||||
| # Local variables: | ||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||
| # time-stamp-start: "scriptversion=" | ||||
| # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||
| # time-stamp-end: "$" | ||||
| # End: | ||||
|   | ||||
							
								
								
									
										1418
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1418
									
								
								configure.in
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										43
									
								
								daemons/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								daemons/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| # | ||||
| # 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@ | ||||
|  | ||||
| .PHONY: dmeventd clvmd cmirrord | ||||
|  | ||||
| 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 ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS = clvmd cmirrord dmeventd | ||||
| endif | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| ifeq ("@BUILD_DMEVENTD@", "yes") | ||||
| device-mapper: dmeventd.device-mapper | ||||
| endif | ||||
							
								
								
									
										117
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| # | ||||
| # 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@ | ||||
|  | ||||
| CCS_LIBS = @CCS_LIBS@ | ||||
| CCS_CFLAGS = @CCS_CFLAGS@ | ||||
| CMAN_LIBS = @CMAN_LIBS@ | ||||
| CMAN_CFLAGS = @CMAN_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@ | ||||
| GULM_LIBS = @GULM_LIBS@ | ||||
| GULM_CFLAGS = @GULM_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 gulm,, "@CLVMD@,")) | ||||
| 	SOURCES += clvmd-gulm.c tcp-comms.c | ||||
| 	LMLIBS += $(CCS_LIBS) $(GULM_LIBS) | ||||
| 	CFLAGS += $(CCS_CFLAGS) $(GULM_CFLAGS) | ||||
| 	DEFS += -DUSE_GULM | ||||
| 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 += $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS) | ||||
| 	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-gulm.c tcp-comms.c | ||||
| 	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) | ||||
|  | ||||
| DEFS += -D_REENTRANT | ||||
| CFLAGS += -fno-strict-aliasing | ||||
|  | ||||
| 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) | ||||
							
								
								
									
										75
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| /* | ||||
|  * 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" | ||||
|  | ||||
| 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 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 */ | ||||
|  | ||||
| /* 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 | ||||
| #endif | ||||
							
								
								
									
										504
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										504
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,504 @@ | ||||
| /* | ||||
|  * 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_create_lockspace(LOCKSPACE_NAME, 0600); | ||||
| 	if (!lockspace) { | ||||
| 		if (errno == EEXIST) { | ||||
| 			lockspace = dlm_open_lockspace(LOCKSPACE_NAME); | ||||
| 		} | ||||
| 		if (!lockspace) { | ||||
| 			syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 	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() | ||||
| { | ||||
| 	return cman_get_fd(c_handle); | ||||
| } | ||||
|  | ||||
| static int _get_num_nodes() | ||||
| { | ||||
| 	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() | ||||
| { | ||||
| 	destroy_lvhash(); | ||||
| 	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() | ||||
| { | ||||
| 	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() | ||||
| { | ||||
| 	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 = { | ||||
| 	.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; | ||||
| } | ||||
							
								
								
									
										421
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,421 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  | ||||
|   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 <pthread.h> | ||||
|  | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd.h" | ||||
| #include "lvm-functions.h" | ||||
|  | ||||
| #include "locking.h" | ||||
|  | ||||
| #include <sys/utsname.h> | ||||
|  | ||||
| extern debug_t debug; | ||||
| 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) { | ||||
| 			uname(&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] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK); | ||||
| 		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: | ||||
| 		debug = args[0]; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_RESTART: | ||||
| 		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; | ||||
|     unsigned char lock_flags; | ||||
|     int lock_mode; | ||||
|     char *args = header->node + strlen(header->node) + 1; | ||||
|     int lkid; | ||||
|     int status = 0; | ||||
|     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) { | ||||
| 	lock_hash = (struct dm_hash_table *)client->bits.localsock.private; | ||||
|     } | ||||
|     else { | ||||
| 	lock_hash = dm_hash_create(3); | ||||
| 	if (!lock_hash) | ||||
| 	    return ENOMEM; | ||||
| 	client->bits.localsock.private = (void *)lock_hash; | ||||
|     } | ||||
|  | ||||
|     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) { | ||||
|  | ||||
| 	lkid = (int)(long)dm_hash_lookup(lock_hash, lockname); | ||||
| 	if (lkid == 0) | ||||
| 	    return EINVAL; | ||||
|  | ||||
| 	lvm_do_fs_unlock(); /* Wait for devices */ | ||||
| 	status = sync_unlock(lockname, lkid); | ||||
| 	if (status) | ||||
| 	    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; | ||||
| 	status = sync_lock(lockname, lock_mode, (lock_cmd & LCK_NONBLOCK) ? LCKF_NOQUEUE : 0, &lkid); | ||||
| 	if (status) | ||||
| 	    status = errno; | ||||
| 	else | ||||
| 	    dm_hash_insert(lock_hash, lockname, (void *)(long)lkid); | ||||
|     } | ||||
|  | ||||
|     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; | ||||
| 	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 = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case CLVMD_CMD_LOCK_VG: | ||||
| 	case CLVMD_CMD_VG_BACKUP: | ||||
| 	case CLVMD_CMD_SYNC_NAMES: | ||||
| 	case CLVMD_CMD_LOCK_QUERY: | ||||
| 		/* Nothing to do here */ | ||||
| 		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; | ||||
| 	} | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Called when the client is about to be deleted */ | ||||
| void cmd_client_cleanup(struct local_client *client) | ||||
| { | ||||
|     if (client->bits.localsock.private) { | ||||
|  | ||||
| 	struct dm_hash_node *v; | ||||
| 	struct dm_hash_table *lock_hash = | ||||
| 	    (struct dm_hash_table *)client->bits.localsock.private; | ||||
|  | ||||
| 	dm_hash_iterate(v, lock_hash) { | ||||
| 		int lkid = (int)(long)dm_hash_get_data(lock_hash, v); | ||||
| 		char *lockname = dm_hash_get_key(lock_hash, v); | ||||
|  | ||||
| 		DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid); | ||||
| 		sync_unlock(lockname, lkid); | ||||
| 	} | ||||
|  | ||||
| 	dm_hash_destroy(lock_hash); | ||||
| 	client->bits.localsock.private = 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| static int restart_clvmd(void) | ||||
| { | ||||
| 	char **argv = NULL; | ||||
| 	char *debug_arg = NULL, *lv_name; | ||||
| 	int i, argc = 0, max_locks = 0; | ||||
| 	struct dm_hash_node *hn = NULL; | ||||
|  | ||||
| 	DEBUGLOG("clvmd restart requested\n"); | ||||
|  | ||||
| 	/* Count exclusively-open LVs */ | ||||
| 	hn = NULL; | ||||
| 	do { | ||||
| 		hn = get_next_excl_lock(hn, &lv_name); | ||||
| 		if (lv_name) | ||||
| 			max_locks++; | ||||
| 	} while (hn && *lv_name); | ||||
|  | ||||
| 	/* clvmd + locks (-E uuid) + debug (-d X) + NULL */ | ||||
| 	argv = malloc((max_locks * 2 + 4) * sizeof(*argv)); | ||||
| 	if (!argv) | ||||
| 		goto_out; | ||||
|  | ||||
| 	/* | ||||
| 	 * Build the command-line | ||||
| 	 */ | ||||
| 	argv[argc++] = strdup("clvmd"); | ||||
| 	if (!argv[0]) | ||||
| 		goto_out; | ||||
|  | ||||
| 	/* Propogate debug options */ | ||||
| 	if (debug) { | ||||
| 		if (!(debug_arg = malloc(16)) || | ||||
| 		    dm_snprintf(debug_arg, 16, "-d%d", (int)debug) < 0) | ||||
| 			goto_out; | ||||
| 		argv[argc++] = debug_arg; | ||||
| 	} | ||||
|  | ||||
| 	/* Now add the exclusively-open LVs */ | ||||
| 	do { | ||||
| 		hn = get_next_excl_lock(hn, &lv_name); | ||||
| 		if (lv_name) { | ||||
| 			argv[argc] = strdup("-E"); | ||||
| 			if (!argv[argc++]) | ||||
| 				goto_out; | ||||
| 			argv[argc] = strdup(lv_name); | ||||
| 			if (!argv[argc++]) | ||||
| 				goto_out; | ||||
|  | ||||
| 			DEBUGLOG("excl lock: %s\n", lv_name); | ||||
| 			hn = get_next_excl_lock(hn, &lv_name); | ||||
| 		} | ||||
| 	} while (hn && *lv_name); | ||||
| 	argv[argc++] = NULL; | ||||
|  | ||||
| 	/* Exec new clvmd */ | ||||
| 	/* NOTE: This will fail when downgrading! */ | ||||
| 	execve(CLVMD_PATH, argv, NULL); | ||||
| out: | ||||
| 	/* We failed */ | ||||
| 	DEBUGLOG("Restart of clvmd failed.\n"); | ||||
|  | ||||
| 	for (i = 0; i < argc && argv[i]; i++) | ||||
| 		free(argv[i]); | ||||
| 	free(argv); | ||||
| 	free(debug_arg); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										33
									
								
								daemons/clvmd/clvmd-common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								daemons/clvmd/clvmd-common.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| /* | ||||
|  * 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 _GNU_SOURCE | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include "libdevmapper.h" | ||||
|  | ||||
| #include "lvm-logging.h" | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										125
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-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 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 { | ||||
| 	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_GULM | ||||
| #  include "tcp-comms.h" | ||||
| struct cluster_ops *init_gulm_cluster(void); | ||||
| #define MAX_CSID_LEN 			GULM_MAX_CSID_LEN | ||||
| #define MAX_CLUSTER_MEMBER_NAME_LEN	GULM_MAX_CLUSTER_MEMBER_NAME_LEN | ||||
| #endif | ||||
|  | ||||
| #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 | ||||
							
								
								
									
										626
									
								
								daemons/clvmd/clvmd-corosync.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										626
									
								
								daemons/clvmd/clvmd-corosync.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,626 @@ | ||||
| /* | ||||
|  * Copyright (C) 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 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> | ||||
| #include <corosync/confdb.h> | ||||
| #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_UNKNOWN, NODE_DOWN, NODE_UP, 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; | ||||
| 	} | ||||
|  | ||||
| 	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, | ||||
| 				COROSYNC_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, | ||||
| 						COROSYNC_CSID_LEN, ninfo); | ||||
| 			} | ||||
| 		} | ||||
| 		ninfo->state = NODE_CLVMD; | ||||
| 	} | ||||
|  | ||||
| 	num_nodes = member_list_entries; | ||||
| } | ||||
|  | ||||
| static int _init_cluster(void) | ||||
| { | ||||
| 	cs_error_t err; | ||||
|  | ||||
| 	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); | ||||
| 	} | ||||
|  | ||||
| 	err = quorum_initialize(&quorum_handle, | ||||
| 				&quorum_callbacks); | ||||
| 	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_create_lockspace(LOCKSPACE_NAME, 0600); | ||||
| 	if (!lockspace) { | ||||
| 		if (errno == EEXIST) { | ||||
| 			lockspace = dlm_open_lockspace(LOCKSPACE_NAME); | ||||
| 		} | ||||
| 		if (!lockspace) { | ||||
| 			syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m"); | ||||
| 			quorum_finalize(quorum_handle); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 	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) | ||||
| { | ||||
| 	DEBUGLOG("cluster_closedown\n"); | ||||
| 	destroy_lvhash(); | ||||
|  | ||||
| 	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() | ||||
| { | ||||
| 	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; | ||||
| 	int somedown = 0; | ||||
|  | ||||
| 	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_DOWN) | ||||
| 			callback(master_client, csid, ninfo->state == NODE_CLVMD); | ||||
| 		if (ninfo->state != NODE_CLVMD) | ||||
| 			somedown = -1; | ||||
| 	} | ||||
| 	return somedown; | ||||
| } | ||||
|  | ||||
| /* 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() | ||||
| { | ||||
| 	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); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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; | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_corosync_ops = { | ||||
| 	.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; | ||||
| } | ||||
							
								
								
									
										1010
									
								
								daemons/clvmd/clvmd-gulm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1010
									
								
								daemons/clvmd/clvmd-gulm.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										9
									
								
								daemons/clvmd/clvmd-gulm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								daemons/clvmd/clvmd-gulm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| extern int get_next_node_csid(void **context, char *csid); | ||||
| extern void add_down_node(char *csid); | ||||
| extern int gulm_fd(void); | ||||
| extern int get_ip_address(const char *node, char *addr); | ||||
| extern void tcp_remove_client(const char *csid); | ||||
| extern int alloc_client(int fd, const char *csid, struct local_client **new_client); | ||||
|  | ||||
| void gulm_add_up_node(const char *csid); | ||||
| int gulm_name_from_csid(const char *csid, char *name); | ||||
							
								
								
									
										693
									
								
								daemons/clvmd/clvmd-openais.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										693
									
								
								daemons/clvmd/clvmd-openais.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,693 @@ | ||||
| /* | ||||
|  * 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); | ||||
|  | ||||
| 	client = malloc(sizeof(struct local_client)); | ||||
| 	if (!client) | ||||
| 	{ | ||||
| 		DEBUGLOG("malloc failed\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	memset(client, 0, sizeof(struct local_client)); | ||||
| 	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 %d\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. %d joined, %d left, %d 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) | ||||
| { | ||||
| 	DEBUGLOG("cluster_closedown\n"); | ||||
| 	destroy_lvhash(); | ||||
|  | ||||
| 	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=%llx\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: %llx\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 = { | ||||
| 	.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; | ||||
| 	else | ||||
| 		return NULL; | ||||
| } | ||||
							
								
								
									
										287
									
								
								daemons/clvmd/clvmd-singlenode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								daemons/clvmd/clvmd-singlenode.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,287 @@ | ||||
| /* | ||||
|  * Copyright (C) 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 | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| #include "locking.h" | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "lvm-functions.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 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) | ||||
| { | ||||
| 	struct sockaddr_un addr; | ||||
| 	mode_t old_mask; | ||||
|  | ||||
| 	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 */ | ||||
| 	fcntl(listen_fd, F_SETFD, 1); | ||||
|  | ||||
| 	memset(&addr, 0, sizeof(addr)); | ||||
| 	memcpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME, | ||||
| 	       sizeof(SINGLENODE_CLVMD_SOCKNAME)); | ||||
| 	addr.sun_family = AF_UNIX; | ||||
|  | ||||
| 	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; | ||||
|  | ||||
| 	r = init_comms(); | ||||
| 	if (r) | ||||
| 		return r; | ||||
|  | ||||
| 	DEBUGLOG("Single-node cluster initialised.\n"); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void _cluster_closedown(void) | ||||
| { | ||||
| 	close_comms(); | ||||
|  | ||||
| 	DEBUGLOG("cluster_closedown\n"); | ||||
| 	destroy_lvhash(); | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	sprintf(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 int *_locks = NULL; | ||||
| static char **_resources = NULL; | ||||
| static int _lock_max = 1; | ||||
| static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER; | ||||
|  | ||||
| /* Real locking */ | ||||
| static int _lock_resource(const char *resource, int mode, int flags, int *lockid) | ||||
| { | ||||
| 	int *_locks_1; | ||||
| 	char **_resources_1; | ||||
| 	int i, j; | ||||
|  | ||||
| 	DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", | ||||
| 		 resource, flags, mode); | ||||
|  | ||||
|  retry: | ||||
| 	pthread_mutex_lock(&_lock_mutex); | ||||
|  | ||||
| 	/* look for an existing lock for this resource */ | ||||
| 	for (i = 1; i < _lock_max; ++i) { | ||||
| 		if (!_resources[i]) | ||||
| 			break; | ||||
| 		if (!strcmp(_resources[i], resource)) { | ||||
| 			if ((_locks[i] & LCK_TYPE_MASK) == LCK_WRITE || | ||||
| 			    (_locks[i] & LCK_TYPE_MASK) == LCK_EXCL) { | ||||
| 				DEBUGLOG("%s already write/exclusively locked...\n", resource); | ||||
| 				goto maybe_retry; | ||||
| 			} | ||||
| 			if ((mode & LCK_TYPE_MASK) == LCK_WRITE || | ||||
| 			    (mode & LCK_TYPE_MASK) == LCK_EXCL) { | ||||
| 				DEBUGLOG("%s already locked and WRITE/EXCL lock requested...\n", | ||||
| 					 resource); | ||||
| 				goto maybe_retry; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (i == _lock_max) { /* out of lock slots, extend */ | ||||
| 		_locks_1 = dm_realloc(_locks, 2 * _lock_max * sizeof(int)); | ||||
| 		if (!_locks_1) | ||||
| 			return 1; /* fail */ | ||||
| 		_locks = _locks_1; | ||||
| 		_resources_1 = dm_realloc(_resources, 2 * _lock_max * sizeof(char *)); | ||||
| 		if (!_resources_1) { | ||||
| 			/* _locks may get realloc'd twice, but that should be safe */ | ||||
| 			return 1; /* fail */ | ||||
| 		} | ||||
| 		_resources = _resources_1; | ||||
| 		/* clear the new resource entries */ | ||||
| 		for (j = _lock_max; j < 2 * _lock_max; ++j) | ||||
| 			_resources[j] = NULL; | ||||
| 		_lock_max = 2 * _lock_max; | ||||
| 	} | ||||
|  | ||||
| 	/* resource is not currently locked, grab it */ | ||||
|  | ||||
| 	*lockid = i; | ||||
| 	_locks[i] = mode; | ||||
| 	_resources[i] = dm_strdup(resource); | ||||
|  | ||||
| 	DEBUGLOG("%s locked -> %d\n", resource, i); | ||||
|  | ||||
| 	pthread_mutex_unlock(&_lock_mutex); | ||||
| 	return 0; | ||||
|  maybe_retry: | ||||
| 	pthread_mutex_unlock(&_lock_mutex); | ||||
| 	if (!(flags & LCK_NONBLOCK)) { | ||||
| 		usleep(10000); | ||||
| 		goto retry; | ||||
| 	} | ||||
|  | ||||
| 	return 1; /* fail */ | ||||
| } | ||||
|  | ||||
| static int _unlock_resource(const char *resource, int lockid) | ||||
| { | ||||
| 	DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid); | ||||
| 	if(!_resources[lockid]) { | ||||
| 		DEBUGLOG("(%s) %d not locked\n", resource, lockid); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	if(strcmp(_resources[lockid], resource)) { | ||||
| 		DEBUGLOG("%d has wrong resource (requested %s, got %s)\n", | ||||
| 			 lockid, resource, _resources[lockid]); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	dm_free(_resources[lockid]); | ||||
| 	_resources[lockid] = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	strncpy(buf, "localcluster", buflen); | ||||
| 	buf[buflen - 1] = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static struct cluster_ops _cluster_singlenode_ops = { | ||||
| 	.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; | ||||
| 	else | ||||
| 		return NULL; | ||||
| } | ||||
							
								
								
									
										2240
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2240
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										123
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| /* | ||||
|  * 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 */ | ||||
| 	struct local_client *pipe_client; | ||||
| 	pthread_t threadid; | ||||
| 	enum { PRE_COMMAND, POST_COMMAND, QUIT } state; | ||||
| 	pthread_mutex_t mutex;	/* Main thread and worker synchronisation */ | ||||
| 	pthread_cond_t cond; | ||||
|  | ||||
| 	pthread_mutex_t reply_mutex;	/* Protect reply structure */ | ||||
| }; | ||||
|  | ||||
| /* 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, const char *buf, | ||||
| 			    int len, const char *csid); | ||||
| extern void debuglog(const char *fmt, ... ) | ||||
|   __attribute__ ((format(printf, 1, 2))); | ||||
|  | ||||
| int sync_lock(const char *resource, int mode, int flags, int *lockid); | ||||
| int sync_unlock(const char *resource, int lockid); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										947
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										947
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,947 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
|  | ||||
| #include "lvm-types.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%s)", cmdl, command, type, scope, | ||||
| 		cmdl & LCK_NONBLOCK   ? "|NONBLOCK" : "", | ||||
| 		cmdl & LCK_HOLD       ? "|HOLD" : "", | ||||
| 		cmdl & LCK_LOCAL      ? "|LOCAL" : "", | ||||
| 		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)", 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_CONVERT ? "CONVERT|" : ""); | ||||
|  | ||||
| 	if (len > 1) | ||||
| 		buf[len - 2] = ' '; | ||||
| 	else | ||||
| 		buf[0] = '\0'; | ||||
|  | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| char *get_last_lvm_error() | ||||
| { | ||||
| 	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 void insert_info(const char *resource, struct lv_info *lvi) | ||||
| { | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	dm_hash_insert(lv_hash, resource, lvi); | ||||
| 	pthread_mutex_unlock(&lv_hash_lock); | ||||
| } | ||||
|  | ||||
| static void remove_info(const char *resource) | ||||
| { | ||||
| 	pthread_mutex_lock(&lv_hash_lock); | ||||
| 	dm_hash_remove(lv_hash, resource); | ||||
| 	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() | ||||
| { | ||||
| 	/* Create hash table for keeping LV locks & status */ | ||||
| 	lv_hash = dm_hash_create(100); | ||||
| 	pthread_mutex_init(&lv_hash_lock, NULL); | ||||
| 	pthread_mutex_init(&lvm_lock, NULL); | ||||
| } | ||||
|  | ||||
| /* Called at shutdown to tidy the lockspace */ | ||||
| void destroy_lvhash() | ||||
| { | ||||
| 	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)); | ||||
| 		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 && lvi->lock_mode == mode) { | ||||
| 		DEBUGLOG("hold_lock, lock mode %d already held\n", mode); | ||||
| 		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; | ||||
|  | ||||
| 		if (status) { | ||||
| 			DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode, | ||||
| 				 strerror(errno)); | ||||
| 		} | ||||
| 		errno = saved_errno; | ||||
| 	} else { | ||||
| 		lvi = malloc(sizeof(struct lv_info)); | ||||
| 		if (!lvi) | ||||
| 			return -1; | ||||
|  | ||||
| 		lvi->lock_mode = mode; | ||||
| 		status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id); | ||||
| 		saved_errno = errno; | ||||
| 		if (status) { | ||||
| 			free(lvi); | ||||
| 			DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode, | ||||
| 				 strerror(errno)); | ||||
| 		} else | ||||
| 			insert_info(resource, lvi); | ||||
|  | ||||
| 		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); | ||||
| 		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 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 && (lock_flags & 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)) | ||||
| 		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 (lock_flags & 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) { | ||||
| 		memlock_inc(cmd); | ||||
| 		if (!lv_resume(cmd, resource, 0)) { | ||||
| 			memlock_dec(cmd); | ||||
| 			goto error; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Now activate it */ | ||||
| 	if (!lv_activate(cmd, resource, exclusive)) | ||||
| 		goto error; | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| error: | ||||
| 	if (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 lock_flags) | ||||
| { | ||||
| 	int oldmode; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("do_resume_lv, lock not already held\n"); | ||||
| 		return 0;	/* We don't need to do anything */ | ||||
| 	} | ||||
|  | ||||
| 	if (!lv_resume_if_active(cmd, resource, (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Suspend the device if active */ | ||||
| static int do_suspend_lv(char *resource, unsigned char lock_flags) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	struct lvinfo lvi; | ||||
| 	unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("do_suspend_lv, lock not already held\n"); | ||||
| 		return 0; /* Not active, so it's OK */ | ||||
| 	} | ||||
|  | ||||
| 	/* Only suspend it if it exists */ | ||||
| 	if (!lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lvi.exists && !lv_suspend_if_active(cmd, resource, origin_only)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int do_deactivate_lv(char *resource, unsigned char lock_flags) | ||||
| { | ||||
| 	int oldmode; | ||||
| 	int status; | ||||
|  | ||||
| 	/* Is it open ? */ | ||||
| 	oldmode = get_current_lock(resource); | ||||
| 	if (oldmode == -1 && (lock_flags & 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)) | ||||
| 		return EIO; | ||||
|  | ||||
| 	if (lock_flags & 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 = NULL; | ||||
|  | ||||
| 	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; | ||||
| 	} | ||||
|  | ||||
| 	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, memlock = %d\n", | ||||
| 		 resource, decode_locking_cmd(command), decode_flags(lock_flags), memlock()); | ||||
|  | ||||
| 	if (!cmd->config_valid || 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); | ||||
| 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE) | ||||
| 		init_mirror_in_sync(1); | ||||
|  | ||||
| 	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, lock_flags, LCK_EXCL); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_SUSPEND: | ||||
| 		status = do_suspend_lv(resource, lock_flags); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_UNLOCK: | ||||
| 	case LCK_LV_RESUME:	/* if active */ | ||||
| 		status = do_resume_lv(resource, lock_flags); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_ACTIVATE: | ||||
| 		status = do_activate_lv(resource, lock_flags, LCK_READ); | ||||
| 		break; | ||||
|  | ||||
| 	case LCK_LV_DEACTIVATE: | ||||
| 		status = do_deactivate_lv(resource, 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); | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
|  | ||||
| 	DEBUGLOG("Command return is %d, memlock is %d\n", status, memlock()); | ||||
| 	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 && | ||||
| 	    (lock_flags & LCK_CLUSTER_VG)) { | ||||
| 		DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n", | ||||
| 			 resource, decode_locking_cmd(command), decode_flags(lock_flags)); | ||||
|  | ||||
| 		if (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 && | ||||
| 	    (lock_flags & 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 (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() | ||||
| { | ||||
| 	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; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Only called at gulm startup. Drop any leftover VG or P_orphan locks | ||||
|    that might be hanging around if we died for any reason | ||||
| */ | ||||
| static void drop_vg_locks(void) | ||||
| { | ||||
| 	char vg[128]; | ||||
| 	char line[255]; | ||||
| 	FILE *vgs = | ||||
| 	    popen | ||||
| 	    (LVM_PATH " pvs  --config 'log{command_names=0 prefix=\"\"}' --nolocking --noheadings -o vg_name", "r"); | ||||
|  | ||||
| 	sync_unlock("P_" VG_ORPHANS, LCK_EXCL); | ||||
| 	sync_unlock("P_" VG_GLOBAL, LCK_EXCL); | ||||
|  | ||||
| 	if (!vgs) | ||||
| 		return; | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), vgs)) { | ||||
| 		char *vgend; | ||||
| 		char *vgstart; | ||||
|  | ||||
| 		if (line[strlen(line)-1] == '\n') | ||||
| 			line[strlen(line)-1] = '\0'; | ||||
|  | ||||
| 		vgstart = line + strspn(line, " "); | ||||
| 		vgend = vgstart + strcspn(vgstart, " "); | ||||
| 		*vgend = '\0'; | ||||
|  | ||||
| 		if (strncmp(vgstart, "WARNING:", 8) == 0) | ||||
| 			continue; | ||||
|  | ||||
| 		sprintf(vg, "V_%s", vgstart); | ||||
| 		sync_unlock(vg, LCK_EXCL); | ||||
|  | ||||
| 	} | ||||
| 	if (fclose(vgs)) | ||||
| 		DEBUGLOG("vgs fclose failed: %s\n", strerror(errno)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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, memlock = %d\n", | ||||
| 		 resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), memlock()); | ||||
|  | ||||
| 	/* P_#global causes a full cache refresh */ | ||||
| 	if (!strcmp(resource, "P_" VG_GLOBAL)) { | ||||
| 		do_refresh_cache(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	pthread_mutex_lock(&lvm_lock); | ||||
| 	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); | ||||
| 	} | ||||
| 	pthread_mutex_unlock(&lvm_lock); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Compare the uuid with the list of exclusive locks that clvmd | ||||
|  * held before it was restarted, so we can get the right kind | ||||
|  * of lock now we are restarting. | ||||
|  */ | ||||
| static int was_ex_lock(char *uuid, char **argv) | ||||
| { | ||||
| 	int optnum = 0; | ||||
| 	char *opt = argv[optnum]; | ||||
|  | ||||
| 	while (opt) { | ||||
| 		if (strcmp(opt, "-E") == 0) { | ||||
| 			opt = argv[++optnum]; | ||||
| 			if (opt && (strcmp(opt, uuid) == 0)) { | ||||
| 				DEBUGLOG("Lock %s is exclusive\n", uuid); | ||||
| 				return 1; | ||||
| 			} | ||||
| 		} | ||||
| 		opt = argv[++optnum]; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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 void *get_initial_state(char **argv) | ||||
| { | ||||
| 	int lock_mode; | ||||
| 	char lv[64], vg[64], flags[25], vg_flags[25]; | ||||
| 	char uuid[65]; | ||||
| 	char line[255]; | ||||
| 	FILE *lvs = | ||||
| 	    popen | ||||
| 	    (LVM_PATH " lvs  --config 'log{command_names=0 prefix=\"\"}' --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr", | ||||
| 	     "r"); | ||||
|  | ||||
| 	if (!lvs) | ||||
| 		return NULL; | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), lvs)) { | ||||
| 	        if (sscanf(line, "%s %s %s %s\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'; | ||||
|  | ||||
| 				lock_mode = LCK_READ; | ||||
|  | ||||
| 				/* Look for this lock in the list of EX locks | ||||
| 				   we were passed on the command-line */ | ||||
| 				if (was_ex_lock(uuid, argv)) | ||||
| 					lock_mode = LCK_EXCL; | ||||
|  | ||||
| 				DEBUGLOG("getting initial lock for %s\n", uuid); | ||||
| 				hold_lock(uuid, lock_mode, LCKF_NOQUEUE); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if (fclose(lvs)) | ||||
| 		DEBUGLOG("lvs fclose failed: %s\n", strerror(errno)); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| 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", 1); | ||||
|  | ||||
| 	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", | ||||
| 					  ""); | ||||
| 		if (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); | ||||
|  | ||||
| 	free_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(int using_gulm, char **argv) | ||||
| { | ||||
| 	if (!(cmd = create_toolcontext(1, NULL))) { | ||||
| 		log_error("Failed to allocate command context"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (stored_errno()) { | ||||
| 		destroy_toolcontext(cmd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Use LOG_DAEMON for syslog messages instead of LOG_USER */ | ||||
| 	init_syslog(LOG_DAEMON); | ||||
| 	openlog("clvmd", LOG_PID, LOG_DAEMON); | ||||
| 	cmd->cmd_line = "clvmd"; | ||||
|  | ||||
| 	/* Check lvm.conf is setup for cluster-LVM */ | ||||
| 	check_config(); | ||||
| 	init_ignore_suspended_devices(1); | ||||
|  | ||||
| 	/* Remove any non-LV locks that may have been left around */ | ||||
| 	if (using_gulm) | ||||
| 		drop_vg_locks(); | ||||
|  | ||||
| 	get_initial_state(argv); | ||||
|  | ||||
| 	/* 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; | ||||
| } | ||||
							
								
								
									
										41
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  * 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(int using_gulm, char **argv); | ||||
| 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 | ||||
							
								
								
									
										380
									
								
								daemons/clvmd/refresh_clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								daemons/clvmd/refresh_clvmd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * 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; | ||||
|  | ||||
| 	/* Open local socket */ | ||||
| 	if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { | ||||
| 		fprintf(stderr, "Local socket creation failed: %s", strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	memset(&sockaddr, 0, sizeof(sockaddr)); | ||||
| 	memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME)); | ||||
|  | ||||
| 	sockaddr.sun_family = AF_UNIX; | ||||
|  | ||||
| 	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; | ||||
| 	int 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, | ||||
| 			  int len) | ||||
| { | ||||
| 	head->cmd = cmd; | ||||
| 	head->status = 0; | ||||
| 	head->flags = 0; | ||||
| 	head->clientid = 0; | ||||
| 	head->arglen = len; | ||||
|  | ||||
| 	if (node) { | ||||
| 		/* | ||||
| 		 * Allow a couple of special node names: | ||||
| 		 * "*" for all nodes, | ||||
| 		 * "." for the local node only | ||||
| 		 */ | ||||
| 		if (strcmp(node, "*") == 0) { | ||||
| 			head->node[0] = '\0'; | ||||
| 		} else if (strcmp(node, ".") == 0) { | ||||
| 			head->node[0] = '\0'; | ||||
| 			head->flags = CLVMD_FLAG_LOCAL; | ||||
| 		} else | ||||
| 			strcpy(head->node, node); | ||||
| 	} else | ||||
| 		head->node[0] = '\0'; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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); | ||||
| 	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 = dm_malloc(sizeof(lvm_response_t) * num_responses + | ||||
| 			    sizeof(int) * 2); | ||||
| 	if (!*response) { | ||||
| 		errno = ENOMEM; | ||||
| 		status = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	rarray = *response; | ||||
|  | ||||
| 	/* 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); | ||||
| 			free(*response); | ||||
| 			errno = ENOMEM; | ||||
| 			status = -1; | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		strcpy(rarray[i].response, inptr); | ||||
| 		rarray[i].len = strlen(inptr); | ||||
| 		inptr += strlen(inptr) + 1; | ||||
| 		i++; | ||||
| 	} | ||||
| 	*num = num_responses; | ||||
| 	*response = rarray; | ||||
|  | ||||
|       out: | ||||
| 	if (retbuf) | ||||
| 		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?"*":".", 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?"*":".", 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 = "*"; | ||||
| 	else | ||||
| 		nodes = "."; | ||||
|  | ||||
| 	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; | ||||
| } | ||||
							
								
								
									
										19
									
								
								daemons/clvmd/refresh_clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								daemons/clvmd/refresh_clvmd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
|  * Copyright (C) 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 | ||||
|  */ | ||||
|  | ||||
|  | ||||
| int refresh_clvmd(int all_nodes); | ||||
| int restart_clvmd(int all_nodes); | ||||
| int debug_clvmd(int level, int clusterwide); | ||||
|  | ||||
							
								
								
									
										502
									
								
								daemons/clvmd/tcp-comms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										502
									
								
								daemons/clvmd/tcp-comms.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,502 @@ | ||||
| /* | ||||
|  *  Copyright (C) 2002-2003 Sistina Software, Inc. All rights reserved. | ||||
|  *  Copyright (C) 2004-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 inter-clvmd communications for a system without CMAN. | ||||
|  * There is a listening TCP socket which accepts new connections in the | ||||
|  * normal way. | ||||
|  * It can also make outgoing connnections to the other clvmd nodes. | ||||
|  */ | ||||
|  | ||||
| #include "clvmd-common.h" | ||||
|  | ||||
| #include <pthread.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <stdint.h> | ||||
| #include <fcntl.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include <errno.h> | ||||
| #include <syslog.h> | ||||
| #include <netdb.h> | ||||
| #include <assert.h> | ||||
|  | ||||
| #include "clvm.h" | ||||
| #include "clvmd-comms.h" | ||||
| #include "clvmd.h" | ||||
| #include "clvmd-gulm.h" | ||||
|  | ||||
| #define DEFAULT_TCP_PORT 21064 | ||||
|  | ||||
| static int listen_fd = -1; | ||||
| static int tcp_port; | ||||
| struct dm_hash_table *sock_hash; | ||||
|  | ||||
| static int get_our_ip_address(char *addr, int *family); | ||||
| static int read_from_tcpsock(struct local_client *fd, char *buf, int len, char *csid, | ||||
| 			     struct local_client **new_client); | ||||
|  | ||||
| /* Called by init_cluster() to open up the listening socket */ | ||||
| int init_comms(unsigned short port) | ||||
| { | ||||
|     struct sockaddr_in6 addr; | ||||
|  | ||||
|     sock_hash = dm_hash_create(100); | ||||
|     tcp_port = port ? : DEFAULT_TCP_PORT; | ||||
|  | ||||
|     listen_fd = socket(AF_INET6, SOCK_STREAM, 0); | ||||
|  | ||||
|     if (listen_fd < 0) | ||||
|     { | ||||
| 	return -1; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	int one = 1; | ||||
| 	setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); | ||||
| 	setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int)); | ||||
|     } | ||||
|  | ||||
|     memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY | ||||
|     addr.sin6_family = AF_INET6; | ||||
|     addr.sin6_port = htons(tcp_port); | ||||
|  | ||||
|     if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) | ||||
|     { | ||||
| 	DEBUGLOG("Can't bind to port: %s\n", strerror(errno)); | ||||
| 	syslog(LOG_ERR, "Can't bind to port %d, is clvmd already running ?", tcp_port); | ||||
| 	close(listen_fd); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     listen(listen_fd, 5); | ||||
|  | ||||
|     /* Set Close-on-exec */ | ||||
|     fcntl(listen_fd, F_SETFD, 1); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void tcp_remove_client(const char *c_csid) | ||||
| { | ||||
|     struct local_client *client; | ||||
|     char csid[GULM_MAX_CSID_LEN]; | ||||
|     unsigned int i; | ||||
|     memcpy(csid, c_csid, sizeof csid); | ||||
|     DEBUGLOG("tcp_remove_client\n"); | ||||
|  | ||||
|     /* Don't actually close the socket here - that's the | ||||
|        job of clvmd.c whch will do the job when it notices the | ||||
|        other end has gone. We just need to remove the client(s) from | ||||
|        the hash table so we don't try to use it for sending any more */ | ||||
|     for (i = 0; i < 2; i++) | ||||
|     { | ||||
| 	client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
| 	if (client) | ||||
| 	{ | ||||
| 	    dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
| 	    client->removeme = 1; | ||||
| 	    close(client->fd); | ||||
| 	} | ||||
| 	/* Look for a mangled one too, on the 2nd iteration. */ | ||||
| 	csid[0] ^= 0x80; | ||||
|     } | ||||
| } | ||||
|  | ||||
| int alloc_client(int fd, const char *c_csid, struct local_client **new_client) | ||||
| { | ||||
|     struct local_client *client; | ||||
|     char csid[GULM_MAX_CSID_LEN]; | ||||
|     memcpy(csid, c_csid, sizeof csid); | ||||
|  | ||||
|     DEBUGLOG("alloc_client %d csid = %s\n", fd, print_csid(csid)); | ||||
|  | ||||
|     /* Create a local_client and return it */ | ||||
|     client = malloc(sizeof(struct local_client)); | ||||
|     if (!client) | ||||
|     { | ||||
| 	DEBUGLOG("malloc failed\n"); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     memset(client, 0, sizeof(struct local_client)); | ||||
|     client->fd = fd; | ||||
|     client->type = CLUSTER_DATA_SOCK; | ||||
|     client->callback = read_from_tcpsock; | ||||
|     if (new_client) | ||||
| 	*new_client = client; | ||||
|  | ||||
|     /* Add to our list of node sockets */ | ||||
|     if (dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN)) | ||||
|     { | ||||
| 	DEBUGLOG("alloc_client mangling CSID for second connection\n"); | ||||
| 	/* This is a duplicate connection but we can't close it because | ||||
| 	   the other end may already have started sending. | ||||
| 	   So, we mangle the IP address and keep it, all sending will | ||||
| 	   go out of the main FD | ||||
| 	*/ | ||||
| 	csid[0] ^= 0x80; | ||||
| 	client->bits.net.flags = 1; /* indicate mangled CSID */ | ||||
|  | ||||
|         /* If it still exists then kill the connection as we should only | ||||
|            ever have one incoming connection from each node */ | ||||
|         if (dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN)) | ||||
|         { | ||||
| 	    DEBUGLOG("Multiple incoming connections from node\n"); | ||||
|             syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]); | ||||
|  | ||||
| 	    free(client); | ||||
|             errno = ECONNREFUSED; | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
|     dm_hash_insert_binary(sock_hash, csid, GULM_MAX_CSID_LEN, client); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int get_main_gulm_cluster_fd() | ||||
| { | ||||
|     return listen_fd; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* Read on main comms (listen) socket, accept it */ | ||||
| int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, const char *csid, | ||||
| 			struct local_client **new_client) | ||||
| { | ||||
|     int newfd; | ||||
|     struct sockaddr_in6 addr; | ||||
|     socklen_t addrlen = sizeof(addr); | ||||
|     int status; | ||||
|     char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN]; | ||||
|  | ||||
|     DEBUGLOG("cluster_fd_callback\n"); | ||||
|     *new_client = NULL; | ||||
|     newfd = accept(listen_fd, (struct sockaddr *)&addr, &addrlen); | ||||
|  | ||||
|     DEBUGLOG("cluster_fd_callback, newfd=%d (errno=%d)\n", newfd, errno); | ||||
|     if (!newfd) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "error in accept: %m"); | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; /* Don't return an error or clvmd will close the listening FD */ | ||||
|     } | ||||
|  | ||||
|     /* Check that the client is a member of the cluster | ||||
|        and reject if not. | ||||
|     */ | ||||
|     if (gulm_name_from_csid((char *)&addr.sin6_addr, name) < 0) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "Got connect from non-cluster node %s\n", | ||||
| 	       print_csid((char *)&addr.sin6_addr)); | ||||
| 	DEBUGLOG("Got connect from non-cluster node %s\n", | ||||
| 		 print_csid((char *)&addr.sin6_addr)); | ||||
| 	close(newfd); | ||||
|  | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     status = alloc_client(newfd, (char *)&addr.sin6_addr, new_client); | ||||
|     if (status) | ||||
|     { | ||||
| 	DEBUGLOG("cluster_fd_callback, alloc_client failed, status = %d\n", status); | ||||
| 	close(newfd); | ||||
| 	/* See above... */ | ||||
| 	errno = EAGAIN; | ||||
| 	return -1; | ||||
|     } | ||||
|     DEBUGLOG("cluster_fd_callback, returning %d, %p\n", newfd, *new_client); | ||||
|     return newfd; | ||||
| } | ||||
|  | ||||
| /* Try to get at least 'len' bytes from the socket */ | ||||
| static int really_read(int fd, char *buf, int len) | ||||
| { | ||||
| 	int got, offset; | ||||
|  | ||||
| 	got = offset = 0; | ||||
|  | ||||
| 	do { | ||||
| 		got = read(fd, buf+offset, len-offset); | ||||
| 		DEBUGLOG("really_read. got %d bytes\n", got); | ||||
| 		offset += got; | ||||
| 	} while (got > 0 && offset < len); | ||||
|  | ||||
| 	if (got < 0) | ||||
| 		return got; | ||||
| 	else | ||||
| 		return offset; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid, | ||||
| 			     struct local_client **new_client) | ||||
| { | ||||
|     struct sockaddr_in6 addr; | ||||
|     socklen_t slen = sizeof(addr); | ||||
|     struct clvm_header *header = (struct clvm_header *)buf; | ||||
|     int status; | ||||
|     uint32_t arglen; | ||||
|  | ||||
|     DEBUGLOG("read_from_tcpsock fd %d\n", client->fd); | ||||
|     *new_client = NULL; | ||||
|  | ||||
|     /* Get "csid" */ | ||||
|     getpeername(client->fd, (struct sockaddr *)&addr, &slen); | ||||
|     memcpy(csid, &addr.sin6_addr, GULM_MAX_CSID_LEN); | ||||
|  | ||||
|     /* Read just the header first, then get the rest if there is any. | ||||
|      * Stream sockets, sigh. | ||||
|      */ | ||||
|     status = really_read(client->fd, buf, sizeof(struct clvm_header)); | ||||
|     if (status > 0) | ||||
|     { | ||||
| 	    int status2; | ||||
|  | ||||
| 	    arglen = ntohl(header->arglen); | ||||
|  | ||||
| 	    /* Get the rest */ | ||||
| 	    if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE) | ||||
| 	    { | ||||
| 		    status2 = really_read(client->fd, buf+status, arglen); | ||||
| 		    if (status2 > 0) | ||||
| 			    status += status2; | ||||
| 		    else | ||||
| 			    status = status2; | ||||
| 	    } | ||||
|     } | ||||
|  | ||||
|     DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno); | ||||
|  | ||||
|     /* Remove it from the hash table if there's an error, clvmd will | ||||
|        remove the socket from its lists and free the client struct */ | ||||
|     if (status == 0 || | ||||
| 	(status < 0 && errno != EAGAIN && errno != EINTR)) | ||||
|     { | ||||
| 	char remcsid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
| 	memcpy(remcsid, csid, GULM_MAX_CSID_LEN); | ||||
| 	close(client->fd); | ||||
|  | ||||
| 	/* If the csid was mangled, then make sure we remove the right entry */ | ||||
| 	if (client->bits.net.flags) | ||||
| 	    remcsid[0] ^= 0x80; | ||||
| 	dm_hash_remove_binary(sock_hash, remcsid, GULM_MAX_CSID_LEN); | ||||
|  | ||||
| 	/* Tell cluster manager layer */ | ||||
| 	add_down_node(remcsid); | ||||
|     } | ||||
|     else { | ||||
| 	    gulm_add_up_node(csid); | ||||
| 	    /* Send it back to clvmd */ | ||||
| 	    process_message(client, buf, status, csid); | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| int gulm_connect_csid(const char *csid, struct local_client **newclient) | ||||
| { | ||||
|     int fd; | ||||
|     struct sockaddr_in6 addr; | ||||
|     int status; | ||||
|     int one = 1; | ||||
|  | ||||
|     DEBUGLOG("Connecting socket\n"); | ||||
|     fd = socket(PF_INET6, SOCK_STREAM, 0); | ||||
|  | ||||
|     if (fd < 0) | ||||
|     { | ||||
| 	syslog(LOG_ERR, "Unable to create new socket: %m"); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     addr.sin6_family = AF_INET6; | ||||
|     memcpy(&addr.sin6_addr, csid, GULM_MAX_CSID_LEN); | ||||
|     addr.sin6_port = htons(tcp_port); | ||||
|  | ||||
|     DEBUGLOG("Connecting socket %d\n", fd); | ||||
|     if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) | ||||
|     { | ||||
| 	/* "Connection refused" is "normal" because clvmd may not yet be running | ||||
| 	 * on that node. | ||||
| 	 */ | ||||
| 	if (errno != ECONNREFUSED) | ||||
| 	{ | ||||
| 	    syslog(LOG_ERR, "Unable to connect to remote node: %m"); | ||||
| 	} | ||||
| 	DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno)); | ||||
| 	close(fd); | ||||
| 	return -1; | ||||
|     } | ||||
|  | ||||
|     /* Set Close-on-exec */ | ||||
|     fcntl(fd, F_SETFD, 1); | ||||
|     setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int)); | ||||
|  | ||||
|     status = alloc_client(fd, csid, newclient); | ||||
|     if (status) | ||||
| 	close(fd); | ||||
|     else | ||||
| 	add_client(*newclient); | ||||
|  | ||||
|     /* If we can connect to it, it must be running a clvmd */ | ||||
|     gulm_add_up_node(csid); | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| /* Send a message to a known CSID */ | ||||
| static int tcp_send_message(void *buf, int msglen, const char *csid, const char *errtext) | ||||
| { | ||||
|     int status; | ||||
|     struct local_client *client; | ||||
|     char ourcsid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
|     assert(csid); | ||||
|  | ||||
|     DEBUGLOG("tcp_send_message, csid = %s, msglen = %d\n", print_csid(csid), msglen); | ||||
|  | ||||
|     /* Don't connect to ourself */ | ||||
|     get_our_gulm_csid(ourcsid); | ||||
|     if (memcmp(csid, ourcsid, GULM_MAX_CSID_LEN) == 0) | ||||
| 	return msglen; | ||||
|  | ||||
|     client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN); | ||||
|     if (!client) | ||||
|     { | ||||
| 	status = gulm_connect_csid(csid, &client); | ||||
| 	if (status) | ||||
| 	    return -1; | ||||
|     } | ||||
|     DEBUGLOG("tcp_send_message, fd = %d\n", client->fd); | ||||
|  | ||||
|     return write(client->fd, buf, msglen); | ||||
| } | ||||
|  | ||||
|  | ||||
| int gulm_cluster_send_message(void *buf, int msglen, const char *csid, const char *errtext) | ||||
| { | ||||
|     int status=0; | ||||
|  | ||||
|     DEBUGLOG("cluster send message, csid = %p, msglen = %d\n", csid, msglen); | ||||
|  | ||||
|     /* If csid is NULL then send to all known (not just connected) nodes */ | ||||
|     if (!csid) | ||||
|     { | ||||
| 	void *context = NULL; | ||||
| 	char loop_csid[GULM_MAX_CSID_LEN]; | ||||
|  | ||||
| 	/* Loop round all gulm-known nodes */ | ||||
| 	while (get_next_node_csid(&context, loop_csid)) | ||||
| 	{ | ||||
| 	    status = tcp_send_message(buf, msglen, loop_csid, errtext); | ||||
| 	    if (status == 0 || | ||||
| 		(status < 0 && (errno == EAGAIN || errno == EINTR))) | ||||
| 		break; | ||||
| 	} | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|  | ||||
| 	status = tcp_send_message(buf, msglen, csid, errtext); | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | ||||
| /* To get our own IP address we get the locally bound address of the | ||||
|    socket that's talking to GULM in the assumption(eek) that it will | ||||
|    be on the "right" network in a multi-homed system */ | ||||
| static int get_our_ip_address(char *addr, int *family) | ||||
| { | ||||
| 	struct utsname info; | ||||
|  | ||||
| 	uname(&info); | ||||
| 	get_ip_address(info.nodename, addr); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Public version of above for those that don't care what protocol | ||||
|    we're using */ | ||||
| void get_our_gulm_csid(char *csid) | ||||
| { | ||||
|     static char our_csid[GULM_MAX_CSID_LEN]; | ||||
|     static int got_csid = 0; | ||||
|  | ||||
|     if (!got_csid) | ||||
|     { | ||||
| 	int family; | ||||
|  | ||||
| 	memset(our_csid, 0, sizeof(our_csid)); | ||||
| 	if (get_our_ip_address(our_csid, &family)) | ||||
| 	{ | ||||
| 	    got_csid = 1; | ||||
| 	} | ||||
|     } | ||||
|     memcpy(csid, our_csid, GULM_MAX_CSID_LEN); | ||||
| } | ||||
|  | ||||
| static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6) | ||||
| { | ||||
|    ip6->s6_addr32[0] = 0; | ||||
|    ip6->s6_addr32[1] = 0; | ||||
|    ip6->s6_addr32[2] = htonl(0xffff); | ||||
|    ip6->s6_addr32[3] = ip4->s_addr; | ||||
| } | ||||
|  | ||||
| /* Get someone else's IP address from DNS */ | ||||
| int get_ip_address(const char *node, char *addr) | ||||
| { | ||||
|     struct hostent *he; | ||||
|  | ||||
|     memset(addr, 0, GULM_MAX_CSID_LEN); | ||||
|  | ||||
|     // TODO: what do we do about multi-homed hosts ??? | ||||
|     // CCSs ip_interfaces solved this but some bugger removed it. | ||||
|  | ||||
|     /* Try IPv6 first. The man page for gethostbyname implies that | ||||
|        it will lookup ip6 & ip4 names, but it seems not to */ | ||||
|     he = gethostbyname2(node, AF_INET6); | ||||
|     if (he) | ||||
|     { | ||||
| 	memcpy(addr, he->h_addr_list[0], | ||||
| 	       he->h_length); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	he = gethostbyname2(node, AF_INET); | ||||
| 	if (!he) | ||||
| 	    return -1; | ||||
| 	map_v4_to_v6((struct in_addr *)he->h_addr_list[0], (struct in6_addr *)addr); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| char *print_csid(const char *csid) | ||||
| { | ||||
|     static char buf[128]; | ||||
|     int *icsid = (int *)csid; | ||||
|  | ||||
|     sprintf(buf, "[%x.%x.%x.%x]", | ||||
| 	    icsid[0],icsid[1],icsid[2],icsid[3]); | ||||
|  | ||||
|     return buf; | ||||
| } | ||||
							
								
								
									
										13
									
								
								daemons/clvmd/tcp-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								daemons/clvmd/tcp-comms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| #include <netinet/in.h> | ||||
|  | ||||
| #define GULM_MAX_CLUSTER_MESSAGE 1600 | ||||
| #define GULM_MAX_CSID_LEN sizeof(struct in6_addr) | ||||
| #define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128 | ||||
|  | ||||
| extern int init_comms(unsigned short); | ||||
| extern char *print_csid(const char *); | ||||
| int get_main_gulm_cluster_fd(void); | ||||
| int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, const char *csid, struct local_client **new_client); | ||||
| int gulm_cluster_send_message(void *buf, int msglen, const char *csid, const char *errtext); | ||||
| void get_our_gulm_csid(char *csid); | ||||
| int gulm_connect_csid(const char *csid, struct local_client **newclient); | ||||
							
								
								
									
										38
									
								
								daemons/cmirrord/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								daemons/cmirrord/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| # | ||||
| # 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) | ||||
|  | ||||
| cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a | ||||
| 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \ | ||||
| 		$(LVMLIBS) $(LMLIBS) $(LIBS) | ||||
|  | ||||
| install: $(TARGETS) | ||||
| 	$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord | ||||
							
								
								
									
										234
									
								
								daemons/cmirrord/clogd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								daemons/cmirrord/clogd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,234 @@ | ||||
| /* | ||||
|  * 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) | ||||
| { | ||||
| 	unlink(CMIRRORD_PIDFILE); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * daemonize | ||||
|  * | ||||
|  * Performs the steps necessary to become a daemon. | ||||
|  */ | ||||
| static void daemonize(void) | ||||
| { | ||||
| 	int pid; | ||||
| 	int status; | ||||
|  | ||||
| 	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(); | ||||
| 	chdir("/"); | ||||
| 	umask(0); | ||||
|  | ||||
| 	close(0); close(1); close(2); | ||||
| 	open("/dev/null", O_RDONLY); /* reopen stdin */ | ||||
| 	open("/dev/null", O_WRONLY); /* reopen stdout */ | ||||
| 	open("/dev/null", O_WRONLY); /* reopen stderr */ | ||||
|  | ||||
| 	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(); | ||||
| } | ||||
							
								
								
									
										1661
									
								
								daemons/cmirrord/cluster.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1661
									
								
								daemons/cmirrord/cluster.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										76
									
								
								daemons/cmirrord/cluster.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								daemons/cmirrord/cluster.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|  * 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 */ | ||||
							
								
								
									
										33
									
								
								daemons/cmirrord/common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								daemons/cmirrord/common.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| /* | ||||
|  * 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 */ | ||||
							
								
								
									
										210
									
								
								daemons/cmirrord/compat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								daemons/cmirrord/compat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | ||||
| /* | ||||
|  * 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); | ||||
| 	u_rq->request_type = xlate32(u_rq->request_type); | ||||
| 	u_rq->data_size = xlate64(u_rq->data_size); | ||||
|  | ||||
| 	rq->originator = xlate32(rq->originator); | ||||
|  | ||||
| 	v5_data_endian_switch(rq, 1); | ||||
|  | ||||
| 	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 = xlate64(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 == unconverted_version) | ||||
| 			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; | ||||
| } | ||||
							
								
								
									
										25
									
								
								daemons/cmirrord/compat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								daemons/cmirrord/compat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * 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 */ | ||||
							
								
								
									
										1937
									
								
								daemons/cmirrord/functions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1937
									
								
								daemons/cmirrord/functions.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										34
									
								
								daemons/cmirrord/functions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								daemons/cmirrord/functions.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| /* | ||||
|  * 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 */ | ||||
							
								
								
									
										151
									
								
								daemons/cmirrord/link_mon.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								daemons/cmirrord/link_mon.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| /* | ||||
|  * 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; | ||||
| } | ||||
							
								
								
									
										20
									
								
								daemons/cmirrord/link_mon.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								daemons/cmirrord/link_mon.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| /* | ||||
|  * 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 */ | ||||
							
								
								
									
										416
									
								
								daemons/cmirrord/local.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										416
									
								
								daemons/cmirrord/local.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,416 @@ | ||||
| /* | ||||
|  * 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;  /* 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_INFO: | ||||
| 	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_IS_REMOTE_RECOVERING: | ||||
| 	case DM_ULOG_POSTSUSPEND: | ||||
| 		r = cluster_send(rq); | ||||
| 		if (r) { | ||||
| 			u_rq->data_size = 0; | ||||
| 			u_rq->error = r; | ||||
| 			kernel_send(u_rq); | ||||
| 		} | ||||
|  | ||||
| 		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) { | ||||
| 		close(cn_fd); | ||||
| 		return EXIT_KERNEL_BIND; | ||||
| 	} | ||||
|  | ||||
| 	opt = addr.nl_groups; | ||||
| 	r = setsockopt(cn_fd, 270, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt)); | ||||
| 	if (r) { | ||||
| 		close(cn_fd); | ||||
| 		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); | ||||
| 	close(cn_fd); | ||||
| } | ||||
							
								
								
									
										20
									
								
								daemons/cmirrord/local.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								daemons/cmirrord/local.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| /* | ||||
|  * 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 */ | ||||
							
								
								
									
										57
									
								
								daemons/cmirrord/logging.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								daemons/cmirrord/logging.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /* | ||||
|  * 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 | ||||
							
								
								
									
										77
									
								
								daemons/cmirrord/logging.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								daemons/cmirrord/logging.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| /* | ||||
|  * 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...) | ||||
| #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 */ | ||||
							
								
								
									
										3
									
								
								daemons/dmeventd/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								daemons/dmeventd/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| init_fifos | ||||
| fini_fifos | ||||
| daemon_talk | ||||
							
								
								
									
										108
									
								
								daemons/dmeventd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								daemons/dmeventd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| # | ||||
| # Copyright (C) 2005-2010 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) | ||||
|  | ||||
| dmeventd: $(LIB_SHARED) dmeventd.o | ||||
| 	$(CC) $(CFLAGS) $(LDFLAGS) -L. -o $@ dmeventd.o \ | ||||
| 	$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic | ||||
|  | ||||
| dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a | ||||
| 	$(CC) $(CFLAGS) $(LDFLAGS) -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 .exported_symbols_generated | ||||
							
								
								
									
										1883
									
								
								daemons/dmeventd/dmeventd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1883
									
								
								daemons/dmeventd/dmeventd.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										76
									
								
								daemons/dmeventd/dmeventd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								daemons/dmeventd/dmeventd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|  * 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_DAEMON		"/sbin/dmeventd" | ||||
| #define DM_EVENT_LOCKFILE	"/var/lock/dmeventd" | ||||
| #define	DM_EVENT_FIFO_CLIENT	"/var/run/dmeventd-client" | ||||
| #define	DM_EVENT_FIFO_SERVER	"/var/run/dmeventd-server" | ||||
| #define DM_EVENT_PIDFILE	"/var/run/dmeventd.pid" | ||||
|  | ||||
| #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, | ||||
| }; | ||||
|  | ||||
| /* 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. */ | ||||
| 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); | ||||
|  | ||||
| #endif /* __DMEVENTD_DOT_H__ */ | ||||
							
								
								
									
										827
									
								
								daemons/dmeventd/libdevmapper-event.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										827
									
								
								daemons/dmeventd/libdevmapper-event.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,827 @@ | ||||
| /* | ||||
|  * 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 <stdint.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 = NULL; | ||||
|  | ||||
| 	if (!(dmevh = dm_malloc(sizeof(*dmevh)))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	dmevh->dmeventd_path = NULL; | ||||
| 	dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL; | ||||
| 	dmevh->major = dmevh->minor = 0; | ||||
| 	dmevh->mask = 0; | ||||
| 	dmevh->timeout = 0; | ||||
|  | ||||
| 	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); | ||||
|  | ||||
| 	dmevh->dmeventd_path = dm_strdup(dmeventd_path); | ||||
| 	if (!dmevh->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); | ||||
|  | ||||
| 	dmevh->dso = dm_strdup(path); | ||||
| 	if (!dmevh->dso) | ||||
| 		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); | ||||
|  | ||||
| 	dmevh->dev_name = dm_strdup(dev_name); | ||||
| 	if (!dmevh->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); | ||||
|  | ||||
| 	dmevh->uuid = dm_strdup(uuid); | ||||
| 	if (!dmevh->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; | ||||
| 	struct timeval tval = { 0, 0 }; | ||||
| 	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. */ | ||||
| 			FD_ZERO(&fds); | ||||
| 			FD_SET(fifos->server, &fds); | ||||
| 			tval.tv_sec = 1; | ||||
| 			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 < 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) | ||||
| { | ||||
| 	unsigned bytes = 0; | ||||
| 	int ret = 0; | ||||
| 	fd_set fds; | ||||
|  | ||||
| 	size_t size = 2 * sizeof(uint32_t) + msg->size; | ||||
| 	uint32_t *header = alloca(size); | ||||
| 	char *buf = (char *)header; | ||||
| 	char drainbuf[128]; | ||||
| 	struct timeval tval = { 0, 0 }; | ||||
|  | ||||
| 	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) { | ||||
| 		FD_ZERO(&fds); | ||||
| 		FD_SET(fifos->server, &fds); | ||||
| 		tval.tv_usec = 100; | ||||
| 		ret = select(fifos->server + 1, &fds, NULL, NULL, &tval); | ||||
| 		if ((ret < 0) && (errno != EINTR)) { | ||||
| 			log_error("Unable to talk to event daemon"); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (ret == 0) | ||||
| 			break; | ||||
| 		read(fifos->server, drainbuf, 127); | ||||
| 	} | ||||
|  | ||||
| 	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) | ||||
| { | ||||
| 	const char *dso = dso_name ? dso_name : "-"; | ||||
| 	const char *dev = dev_name ? dev_name : "-"; | ||||
| 	const char *fmt = "%d:%d %s %s %u %" PRIu32; | ||||
| 	int msg_size; | ||||
| 	memset(msg, 0, sizeof(*msg)); | ||||
|  | ||||
| 	/* | ||||
| 	 * Set command and pack the arguments | ||||
| 	 * into ASCII message string. | ||||
| 	 */ | ||||
| 	msg->cmd = cmd; | ||||
| 	if (cmd == DM_EVENT_CMD_HELLO) | ||||
| 		fmt = "%d:%d HELLO"; | ||||
| 	if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr, | ||||
| 				    dso, dev, evmask, timeout)) < 0) { | ||||
| 		log_error("_daemon_talk: message allocation failed"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	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 = 0; | ||||
| 		return -EIO; | ||||
| 	} | ||||
|  | ||||
| 	do { | ||||
|  | ||||
| 		dm_free(msg->data); | ||||
| 		msg->data = 0; | ||||
|  | ||||
| 		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 */ | ||||
|  | ||||
| 		close(fifos->client); | ||||
| 		return 1; | ||||
| 	} else if (errno != ENXIO) { | ||||
| 		/* problem */ | ||||
|  | ||||
| 		log_error("%s: Can't open client fifo %s: %s", | ||||
| 			  __func__, fifos->client_path, strerror(errno)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|       start_server: | ||||
| 	/* server is not running */ | ||||
|  | ||||
| 	if (!strncmp(DMEVENTD_PATH, "/", 1) && stat(DMEVENTD_PATH, &statbuf)) { | ||||
| 		log_error("Unable to find dmeventd."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	pid = fork(); | ||||
|  | ||||
| 	if (pid < 0) | ||||
| 		log_error("Unable to 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? */ | ||||
|  | ||||
| 	/* FIXME Make these either configurable or depend directly on dmeventd_path */ | ||||
| 	fifos->client_path = DM_EVENT_FIFO_CLIENT; | ||||
| 	fifos->server_path = DM_EVENT_FIFO_SERVER; | ||||
|  | ||||
| 	/* Open the fifo used to read from the daemon. */ | ||||
| 	if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) { | ||||
| 		log_error("%s: open server fifo %s", | ||||
| 			  __func__, fifos->server_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Lock out anyone else trying to do communication with the daemon. */ | ||||
| 	if (flock(fifos->server, LOCK_EX) < 0) { | ||||
| 		log_error("%s: flock %s", __func__, fifos->server_path); | ||||
| 		close(fifos->server); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| /*	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_error("%s: Can't open client fifo %s: %s", | ||||
| 			  __func__, fifos->client_path, strerror(errno)); | ||||
| 		close(fifos->server); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Initialize client. */ | ||||
| static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	/* init fifos */ | ||||
| 	memset(fifos, 0, sizeof(*fifos)); | ||||
|  | ||||
| 	/* FIXME Make these either configurable or depend directly on dmeventd_path */ | ||||
| 	fifos->client_path = DM_EVENT_FIFO_CLIENT; | ||||
| 	fifos->server_path = DM_EVENT_FIFO_SERVER; | ||||
|  | ||||
| 	if (!_start_daemon(dmeventd_path, fifos)) | ||||
| 		return_0; | ||||
|  | ||||
| 	return init_fifos(fifos); | ||||
| } | ||||
|  | ||||
| void fini_fifos(struct dm_event_fifos *fifos) | ||||
| { | ||||
| 	if (flock(fifos->server, LOCK_UN)) | ||||
| 		log_error("flock unlock %s", fifos->server_path); | ||||
|  | ||||
| 	close(fifos->client); | ||||
| 	close(fifos->server); | ||||
| } | ||||
|  | ||||
| /* 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: device not found"); | ||||
| 		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; | ||||
|  | ||||
| 	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, 0, NULL }; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	uuid = dm_task_get_uuid(dmt); | ||||
|  | ||||
| 	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, 0, NULL }; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		stack; | ||||
| 		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 = NULL; | ||||
| 	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; | ||||
| 	} | ||||
|  | ||||
| 	if (id) | ||||
| 		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, 0, NULL }; | ||||
| 	struct dm_info info; | ||||
|  | ||||
| 	if (!(dmt = _get_device_info(dmevh))) { | ||||
| 		stack; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	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)) { | ||||
| 		ret = -ENOENT; | ||||
| 		stack; | ||||
| 		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); | ||||
| 	dmevh->uuid = dm_strdup(reply_uuid); | ||||
| 	if (!dmevh->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; | ||||
|  | ||||
| 	dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)); | ||||
| 	if (!dmevh->dev_name) { | ||||
| 		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; | ||||
| } | ||||
|  | ||||
| #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, 0, NULL }; | ||||
|  | ||||
| 	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, 0, NULL }; | ||||
|  | ||||
| 	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); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 		*timeout = atoi(p); | ||||
| 	} | ||||
| 	if (msg.data) | ||||
| 		dm_free(msg.data); | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										111
									
								
								daemons/dmeventd/libdevmapper-event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								daemons/dmeventd/libdevmapper-event.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  | ||||
| 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. | ||||
|  */ | ||||
| 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); | ||||
| 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. */ | ||||
| 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 | ||||
							
								
								
									
										11
									
								
								daemons/dmeventd/libdevmapper-event.pc.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								daemons/dmeventd/libdevmapper-event.pc.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| 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 | ||||
							
								
								
									
										25
									
								
								daemons/dmeventd/plugins/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								daemons/dmeventd/plugins/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005 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 mirror snapshot | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| mirror: lvm2 | ||||
| snapshot: lvm2 | ||||
|  | ||||
							
								
								
									
										6
									
								
								daemons/dmeventd/plugins/lvm2/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								daemons/dmeventd/plugins/lvm2/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| dmeventd_lvm2_init | ||||
| dmeventd_lvm2_exit | ||||
| dmeventd_lvm2_lock | ||||
| dmeventd_lvm2_unlock | ||||
| dmeventd_lvm2_pool | ||||
| dmeventd_lvm2_run | ||||
							
								
								
									
										33
									
								
								daemons/dmeventd/plugins/lvm2/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								daemons/dmeventd/plugins/lvm2/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| # | ||||
| # 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 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 | ||||
|  | ||||
| DISTCLEAN_TARGETS += .exported_symbols_generated | ||||
							
								
								
									
										152
									
								
								daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| /* | ||||
|  * 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 "errors.h" | ||||
| #include "libdevmapper-event.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) | ||||
| { | ||||
| 	if (pthread_mutex_trylock(&_event_mutex)) { | ||||
| 		syslog(LOG_NOTICE, "Another thread is handling an event. Waiting..."); | ||||
| 		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; | ||||
| 		} | ||||
| 		/* 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); | ||||
| } | ||||
|  | ||||
							
								
								
									
										39
									
								
								daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  * 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. | ||||
|  */ | ||||
|  | ||||
| #include "libdevmapper.h" | ||||
|  | ||||
| #ifndef _DMEVENTD_LVMWRAP_H | ||||
| #define _DMEVENTD_LVMWRAP_H | ||||
|  | ||||
| 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); | ||||
|  | ||||
| #endif /* _DMEVENTD_LVMWRAP_H */ | ||||
							
								
								
									
										3
									
								
								daemons/dmeventd/plugins/mirror/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								daemons/dmeventd/plugins/mirror/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
							
								
								
									
										39
									
								
								daemons/dmeventd/plugins/mirror/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								daemons/dmeventd/plugins/mirror/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2005, 2008-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@ | ||||
|  | ||||
| INCLUDES += -I$(top_srcdir)/tools -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 | ||||
| CLDFLAGS += -L$(top_builddir)/tools -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 | ||||
|  | ||||
| DISTCLEAN_TARGETS += .exported_symbols_generated | ||||
							
								
								
									
										245
									
								
								daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,245 @@ | ||||
| /* | ||||
|  * Copyright (C) 2005-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 "lvm2cmd.h" | ||||
| #include "errors.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. */ | ||||
|  | ||||
| #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))) | ||||
| 		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; | ||||
|  | ||||
| 	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]; | ||||
| 	char *vg = NULL, *lv = NULL, *layer = NULL; | ||||
|  | ||||
| 	if (strlen(device) > 200)  /* FIXME Use real restriction */ | ||||
| 		return -ENAMETOOLONG;	/* FIXME These return code distinctions are not used so remove them! */ | ||||
|  | ||||
| 	if (!dm_split_lvm_name(dmeventd_lvm2_pool(), device, &vg, &lv, &layer)) { | ||||
| 		syslog(LOG_ERR, "Unable to determine VG name from %s.", | ||||
| 		       device); | ||||
| 		return -ENOMEM;	/* FIXME Replace with generic error return - reason for failure has already got logged */ | ||||
| 	} | ||||
|  | ||||
| 	/* strip off the mirror component designations */ | ||||
| 	layer = strstr(lv, "_mlog"); | ||||
| 	if (layer) | ||||
| 		*layer = '\0'; | ||||
|  | ||||
| 	/* FIXME Is any sanity-checking required on %s? */ | ||||
| 	if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "lvconvert --config devices{ignore_suspended_devices=1} --repair --use-policies %s/%s", vg, lv)) { | ||||
| 		/* this error should be caught above, but doesn't hurt to check again */ | ||||
| 		syslog(LOG_ERR, "Unable to form LVM command: Device name too long."); | ||||
| 		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 LV %s/%s %s.", vg, lv, | ||||
| 	       (r == ECMD_PROCESSED) ? "finished successfully" : "failed"); | ||||
|  | ||||
| 	return (r == ECMD_PROCESSED) ? 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))) | ||||
| { | ||||
| 	int r = dmeventd_lvm2_init(); | ||||
| 	syslog(LOG_INFO, "Monitoring mirror device %s for events.", device); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
							
								
								
									
										3
									
								
								daemons/dmeventd/plugins/snapshot/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								daemons/dmeventd/plugins/snapshot/.exported_symbols
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| process_event | ||||
| register_device | ||||
| unregister_device | ||||
							
								
								
									
										35
									
								
								daemons/dmeventd/plugins/snapshot/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								daemons/dmeventd/plugins/snapshot/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| # | ||||
| # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
| # Copyright (C) 2004-2010 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)/tools -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2 | ||||
| CLDFLAGS += -L$(top_builddir)/tools -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 | ||||
|  | ||||
| DISTCLEAN_TARGETS += .exported_symbols_generated | ||||
							
								
								
									
										262
									
								
								daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007-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 "lvm2cmd.h" | ||||
| #include "errors.h" | ||||
| #include "libdevmapper-event.h" | ||||
| #include "dmeventd_lvm.h" | ||||
|  | ||||
| #include "lvm-string.h" | ||||
|  | ||||
| #include <sys/wait.h> | ||||
| #include <syslog.h> /* FIXME Replace syslog with multilog */ | ||||
| /* 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 snap_status { | ||||
| 	int invalid; | ||||
| 	int used; | ||||
| 	int max; | ||||
| }; | ||||
|  | ||||
| /* FIXME possibly reconcile this with target_percent when we gain | ||||
|    access to regular LVM library here. */ | ||||
| static void _parse_snapshot_params(char *params, struct snap_status *status) | ||||
| { | ||||
| 	char *p; | ||||
| 	/* | ||||
| 	 * xx/xx	-- fractions used/max | ||||
| 	 * Invalid	-- snapshot invalidated | ||||
| 	 * Unknown	-- status unknown | ||||
| 	 */ | ||||
| 	status->used = status->max = 0; | ||||
|  | ||||
| 	if (!strncmp(params, "Invalid", 7)) { | ||||
| 		status->invalid = 1; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * When we return without setting non-zero max, the parent is | ||||
| 	 * responsible for reporting errors. | ||||
| 	 */ | ||||
| 	if (!strncmp(params, "Unknown", 7)) | ||||
| 		return; | ||||
|  | ||||
| 	if (!(p = strstr(params, "/"))) | ||||
| 		return; | ||||
|  | ||||
| 	*p = '\0'; | ||||
| 	p++; | ||||
|  | ||||
| 	status->used = atoi(params); | ||||
| 	status->max = atoi(p); | ||||
| } | ||||
|  | ||||
| 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 *device) | ||||
| { | ||||
| 	char *vg = NULL, *lv = NULL, *layer = NULL; | ||||
| 	char cmd_str[1024]; | ||||
| 	int r = 0; | ||||
|  | ||||
| 	if (!dm_split_lvm_name(dmeventd_lvm2_pool(), device, &vg, &lv, &layer)) { | ||||
| 		syslog(LOG_ERR, "Unable to determine VG name from %s.", device); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (sizeof(cmd_str) <= snprintf(cmd_str, sizeof(cmd_str), | ||||
| 					"lvextend --use-policies %s/%s", vg, lv)) { | ||||
| 		syslog(LOG_ERR, "Unable to form LVM command: Device name too long."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	r = dmeventd_lvm2_run(cmd_str); | ||||
| 	syslog(LOG_INFO, "Extension of snapshot %s/%s %s.", vg, lv, | ||||
| 	       (r == ECMD_PROCESSED) ? "finished successfully" : "failed"); | ||||
| 	return r == ECMD_PROCESSED; | ||||
| } | ||||
|  | ||||
| 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 */ | ||||
| 		dm_split_words(buffer, 3, 0, words); | ||||
|  | ||||
| 		/* 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.", device, words[1]); | ||||
|                         if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL)) | ||||
|                                 syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.", | ||||
|                                        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 snap_status status = { 0 }; | ||||
| 	const char *device = dm_task_get_name(dmt); | ||||
| 	int percent, *percent_check = (int*)private; | ||||
|  | ||||
| 	/* No longer monitoring, waiting for remove */ | ||||
| 	if (!*percent_check) | ||||
| 		return; | ||||
|  | ||||
| 	dmeventd_lvm2_lock(); | ||||
|  | ||||
| 	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms); | ||||
| 	if (!target_type) | ||||
| 		goto out; | ||||
|  | ||||
| 	_parse_snapshot_params(params, &status); | ||||
|  | ||||
| 	if (status.invalid) { | ||||
| 		syslog(LOG_ERR, "Trying to umount invalid snapshot %s...\n", device); | ||||
| 		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... */ | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * 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.max) { | ||||
| 		syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params); | ||||
| 		*percent_check = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	percent = 100 * status.used / status.max; | ||||
| 	if (percent >= *percent_check) { | ||||
| 		/* Usage has raised more than CHECK_STEP since the last | ||||
| 		   time. Run actions. */ | ||||
| 		*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(device)) | ||||
| 			syslog(LOG_ERR, "Failed to extend snapshot %s.", device); | ||||
| 	} | ||||
| out: | ||||
| 	dmeventd_lvm2_unlock(); | ||||
| } | ||||
|  | ||||
| int register_device(const char *device, | ||||
| 		    const char *uuid __attribute__((unused)), | ||||
| 		    int major __attribute__((unused)), | ||||
| 		    int minor __attribute__((unused)), | ||||
| 		    void **private) | ||||
| { | ||||
| 	int *percent_check = (int*)private; | ||||
| 	int r = dmeventd_lvm2_init(); | ||||
|  | ||||
| 	*percent_check = CHECK_MINIMUM; | ||||
|  | ||||
| 	syslog(LOG_INFO, "Monitoring snapshot %s\n", device); | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| 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 snapshot %s\n", | ||||
| 	       device); | ||||
| 	dmeventd_lvm2_exit(); | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										31
									
								
								doc/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								doc/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| # | ||||
| # 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 | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| install_lvm2: $(CONFSRC) | ||||
| 	@if [ ! -e $(confdir)/$(CONFDEST) ]; then \ | ||||
| 		echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST)"; \ | ||||
| 		$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST); \ | ||||
| 	fi | ||||
|  | ||||
| install: install_lvm2 | ||||
|  | ||||
| DISTCLEAN_TARGETS += $(CONFSRC) | ||||
| @@ -1 +0,0 @@ | ||||
| Wow!  This is really incredible documentation! | ||||
							
								
								
									
										577
									
								
								doc/example.conf.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										577
									
								
								doc/example.conf.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,577 @@ | ||||
| # This is an example configuration file for the LVM2 system. | ||||
| # It contains the default settings that would be used if there was no | ||||
| # @DEFAULT_SYS_DIR@/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 @DEFAULT_SYS_DIR@ 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" ] | ||||
|  | ||||
|     # If several entries in the scanned directories correspond to the | ||||
|     # same block device and the tools need to display a name for device, | ||||
|     # all the pathnames are matched against each item in the following | ||||
|     # list of regular expressions in turn and the first match is used. | ||||
|     preferred_names = [ ] | ||||
|  | ||||
|     # Try to avoid using undescriptive /dev/dm-N names, if present. | ||||
|     # preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ] | ||||
|  | ||||
|     # 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. | ||||
|  | ||||
|     # Be careful if there there are symbolic links or multiple filesystem  | ||||
|     # entries for the same device as each name is checked separately against | ||||
|     # the list of patterns.  The effect is that if any name matches any 'a' | ||||
|     # pattern, the device is accepted; otherwise if any name matches any 'r' | ||||
|     # pattern it is rejected; otherwise it is accepted. | ||||
|  | ||||
|     # Don't have more than one filter line active at once: only one gets used. | ||||
|  | ||||
|     # Run vgscan after you change this parameter to ensure that | ||||
|     # the cache file gets regenerated (see below). | ||||
|     # If it doesn't do what you expect, check the output of 'vgscan -vvvv'. | ||||
|  | ||||
|  | ||||
|     # 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 is stored in the @DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@ directory | ||||
|     # in a file called '.cache'. | ||||
|     # It is safe to delete the contents: the tools regenerate it. | ||||
|     # (The old setting 'cache' is still respected if neither of | ||||
|     # these new ones is present.) | ||||
|     cache_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@" | ||||
|     cache_file_prefix = "" | ||||
|  | ||||
|     # 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 | ||||
|  | ||||
|     # By default, if a PV is placed directly upon an md device, LVM2 | ||||
|     # will align its data blocks with the md device's stripe-width. | ||||
|     # 1 enables; 0 disables. | ||||
|     md_chunk_alignment = 1 | ||||
|  | ||||
|     # Default alignment of the start of a data area in MB.  If set to 0, | ||||
|     # a value of 64KB will be used.  Set to 1 for 1MiB, 2 for 2MiB, etc. | ||||
|     # default_data_alignment = @DEFAULT_DATA_ALIGNMENT@ | ||||
|  | ||||
|     # By default, the start of a PV's data area will be a multiple of | ||||
|     # the 'minimum_io_size' or 'optimal_io_size' exposed in sysfs. | ||||
|     # - minimum_io_size - the smallest request the device can perform | ||||
|     #   w/o incurring a read-modify-write penalty (e.g. MD's chunk size) | ||||
|     # - optimal_io_size - the device's preferred unit of receiving I/O | ||||
|     #   (e.g. MD's stripe width) | ||||
|     # minimum_io_size is used if optimal_io_size is undefined (0). | ||||
|     # If md_chunk_alignment is enabled, that detects the optimal_io_size. | ||||
|     # This setting takes precedence over md_chunk_alignment. | ||||
|     # 1 enables; 0 disables. | ||||
|     data_alignment_detection = 1 | ||||
|  | ||||
|     # Alignment (in KB) of start of data area when creating a new PV. | ||||
|     # md_chunk_alignment and data_alignment_detection are disabled if set. | ||||
|     # Set to 0 for the default alignment (see: data_alignment_default) | ||||
|     # or page size, if larger. | ||||
|     data_alignment = 0 | ||||
|  | ||||
|     # By default, the start of the PV's aligned data area will be shifted by | ||||
|     # the 'alignment_offset' exposed in sysfs.  This offset is often 0 but | ||||
|     # may be non-zero; e.g.: certain 4KB sector drives that compensate for | ||||
|     # windows partitioning will have an alignment_offset of 3584 bytes | ||||
|     # (sector 7 is the lowest aligned logical block, the 4KB sectors start | ||||
|     # at LBA -1, and consequently sector 63 is aligned on a 4KB boundary). | ||||
|     # But note that pvcreate --dataalignmentoffset will skip this detection. | ||||
|     # 1 enables; 0 disables. | ||||
|     data_alignment_offset_detection = 1 | ||||
|  | ||||
|     # If, while scanning the system for PVs, LVM2 encounters a device-mapper | ||||
|     # device that has its I/O suspended, it waits for it to become accessible. | ||||
|     # Set this to 1 to skip such devices.  This should only be needed | ||||
|     # in recovery situations. | ||||
|     ignore_suspended_devices = 0 | ||||
|  | ||||
|     # During each LVM operation errors received from each device are counted. | ||||
|     # If the counter of a particular device exceeds the limit set here, no | ||||
|     # further I/O is sent to that device for the remainder of the respective | ||||
|     # operation. Setting the parameter to 0 disables the counters altogether. | ||||
|     disable_after_error_count = 0 | ||||
|  | ||||
|     # Allow use of pvcreate --uuid without requiring --restorefile. | ||||
|     require_restorefile_with_uuid = 1 | ||||
| } | ||||
|  | ||||
| # This section allows you to configure the way in which LVM selects | ||||
| # free space for its Logical Volumes. | ||||
| #allocation { | ||||
| #    When searching for free space to extend an LV, the "cling" | ||||
| #    allocation policy will choose space on the same PVs as the last | ||||
| #    segment of the existing LV.  If there is insufficient space and a | ||||
| #    list of tags is defined here, it will check whether any of them are | ||||
| #    attached to the PVs concerned and then seek to match those PV tags | ||||
| #    between existing extents and new extents. | ||||
| #    Use the special tag "@*" as a wildcard to match any PV tag. | ||||
| #     | ||||
| #    Example: LVs are mirrored between two sites within a single VG. | ||||
| #    PVs are tagged with either @site1 or @site2 to indicate where | ||||
| #    they are situated. | ||||
| # | ||||
| #    cling_tag_list = [ "@site1", "@site2" ] | ||||
| #    cling_tag_list = [ "@*" ] | ||||
| #} | ||||
|  | ||||
| # 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 = "@DEFAULT_SYS_DIR@/@DEFAULT_BACKUP_SUBDIR@" | ||||
|  | ||||
|     # 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 = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@" | ||||
|  | ||||
|     # 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 | ||||
|  | ||||
|     # Default value for --units argument | ||||
|     units = "h" | ||||
|  | ||||
|     # Since version 2.02.54, the tools distinguish between powers of | ||||
|     # 1024 bytes (e.g. KiB, MiB, GiB) and powers of 1000 bytes (e.g. | ||||
|     # KB, MB, GB). | ||||
|     # If you have scripts that depend on the old behaviour, set this to 0 | ||||
|     # temporarily until you update them. | ||||
|     si_unit_consistency = 1 | ||||
|  | ||||
|     # 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 "lvm2". | ||||
|     # format = "lvm2" | ||||
|  | ||||
|     # Location of proc filesystem | ||||
|     proc = "/proc" | ||||
|  | ||||
|     # Type of locking to use. Defaults to local file-based locking (1). | ||||
|     # Turn locking off by setting to 0 (dangerous: risks metadata corruption | ||||
|     # if LVM2 commands get run concurrently). | ||||
|     # Type 2 uses the external shared library locking_library. | ||||
|     # Type 3 uses built-in clustered locking. | ||||
|     # Type 4 uses read-only locking which forbids any operations that might  | ||||
|     # change metadata. | ||||
|     locking_type = 1 | ||||
|  | ||||
|     # Set to 0 to fail when a lock request cannot be satisfied immediately. | ||||
|     wait_for_locks = 1 | ||||
|  | ||||
|     # If using external locking (type 2) and initialisation fails, | ||||
|     # with this set to 1 an attempt will be made to use the built-in | ||||
|     # clustered locking. | ||||
|     # If you are using a customised locking_library you should set this to 0. | ||||
|     fallback_to_clustered_locking = 1 | ||||
|  | ||||
|     # If an attempt to initialise type 2 or type 3 locking failed, perhaps | ||||
|     # because cluster components such as clvmd are not running, with this set | ||||
|     # to 1 an attempt will be made to use local file-based locking (type 1). | ||||
|     # If this succeeds, only commands against local volume groups will proceed. | ||||
|     # Volume Groups marked as clustered will be ignored. | ||||
|     fallback_to_local_locking = 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 = "@DEFAULT_LOCK_DIR@" | ||||
|  | ||||
|     # Whenever there are competing read-only and read-write access requests for | ||||
|     # a volume group's metadata, instead of always granting the read-only | ||||
|     # requests immediately, delay them to allow the read-write requests to be | ||||
|     # serviced.  Without this setting, write access may be stalled by a high | ||||
|     # volume of read-only requests. | ||||
|     # NB. This option only affects locking_type = 1 viz. local file-based | ||||
|     # locking. | ||||
|     prioritise_write_locks = 1 | ||||
|  | ||||
|     # 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" | ||||
|  | ||||
|     # The external locking library to load if locking_type is set to 2. | ||||
|     #   locking_library = "liblvm2clusterlock.so" | ||||
|  | ||||
|     # Treat any internal errors as fatal errors, aborting the process that | ||||
|     # encountered the internal error. Please only enable for debugging. | ||||
|     abort_on_internal_errors = 0 | ||||
|  | ||||
|     # If set to 1, no operations that change on-disk metadata will be permitted. | ||||
|     # Additionally, read-only commands that encounter metadata in need of repair | ||||
|     # will still be allowed to proceed exactly as if the repair had been  | ||||
|     # performed (except for the unchanged vg_seqno). | ||||
|     # Inappropriate use could mess up your system, so seek advice first! | ||||
|     metadata_read_only = 0 | ||||
| } | ||||
|  | ||||
| activation { | ||||
|     # Set to 0 to disable udev synchronisation (if compiled into the binaries). | ||||
|     # Processes will not wait for notification from udev. | ||||
|     # They will continue irrespective of any possible udev processing | ||||
|     # in the background.  You should only use this if udev is not running | ||||
|     # or has rules that ignore the devices LVM2 creates. | ||||
|     # The command line argument --nodevsync takes precedence over this setting. | ||||
|     # If set to 1 when udev is not running, and there are LVM2 processes | ||||
|     # waiting for udev, run 'dmsetup udevcomplete_all' manually to wake them up. | ||||
|     udev_sync = 1 | ||||
|  | ||||
|     # Set to 0 to disable the udev rules installed by LVM2 (if built with | ||||
|     # --enable-udev_rules). LVM2 will then manage the /dev nodes and symlinks | ||||
|     # for active logical volumes directly itself. | ||||
|     # N.B. Manual intervention may be required if this setting is changed | ||||
|     # while any logical volumes are active. | ||||
|     udev_rules = 1 | ||||
|  | ||||
|     # How to fill in missing stripes if activating an incomplete volume. | ||||
|     # Using "error" will make inaccessible parts of the device return | ||||
|     # I/O errors on access.  You can instead use a device path, in which  | ||||
|     # case, that device will be used to in place of missing stripes. | ||||
|     # But note that using anything other than "error" with mirrored  | ||||
|     # or snapshotted volumes is likely to result in data corruption. | ||||
|     missing_stripe_filler = "error" | ||||
|  | ||||
|     # 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", "@*" ] | ||||
|  | ||||
|     # Size (in KB) of each copy operation when mirroring | ||||
|     mirror_region_size = 512 | ||||
|  | ||||
|     # Setting to use when there is no readahead value stored in the metadata. | ||||
|     # | ||||
|     # "none" - Disable readahead. | ||||
|     # "auto" - Use default value chosen by kernel. | ||||
|     readahead = "auto" | ||||
|  | ||||
|     # 'mirror_image_fault_policy' and 'mirror_log_fault_policy' define | ||||
|     # how a device failure affecting a mirror is handled. | ||||
|     # A mirror is composed of mirror images (copies) and a log. | ||||
|     # A disk log ensures that a mirror does not need to be re-synced | ||||
|     # (all copies made the same) every time a machine reboots or crashes. | ||||
|     # | ||||
|     # In the event of a failure, the specified policy will be used to determine | ||||
|     # what happens. This applies to automatic repairs (when the mirror is being | ||||
|     # monitored by dmeventd) and to manual lvconvert --repair when | ||||
|     # --use-policies is given. | ||||
|     # | ||||
|     # "remove" - Simply remove the faulty device and run without it.  If | ||||
|     #            the log device fails, the mirror would convert to using | ||||
|     #            an in-memory log.  This means the mirror will not | ||||
|     #            remember its sync status across crashes/reboots and | ||||
|     #            the entire mirror will be re-synced.  If a | ||||
|     #            mirror image fails, the mirror will convert to a | ||||
|     #            non-mirrored device if there is only one remaining good | ||||
|     #            copy. | ||||
|     # | ||||
|     # "allocate" - Remove the faulty device and try to allocate space on | ||||
|     #            a new device to be a replacement for the failed device. | ||||
|     #            Using this policy for the log is fast and maintains the | ||||
|     #            ability to remember sync state through crashes/reboots. | ||||
|     #            Using this policy for a mirror device is slow, as it | ||||
|     #            requires the mirror to resynchronize the devices, but it | ||||
|     #            will preserve the mirror characteristic of the device. | ||||
|     #            This policy acts like "remove" if no suitable device and | ||||
|     #            space can be allocated for the replacement. | ||||
|     # | ||||
|     # "allocate_anywhere" - Not yet implemented. Useful to place the log device | ||||
|     #            temporarily on same physical volume as one of the mirror | ||||
|     #            images. This policy is not recommended for mirror devices | ||||
|     #            since it would break the redundant nature of the mirror. This | ||||
|     #            policy acts like "remove" if no suitable device and space can | ||||
|     #            be allocated for the replacement. | ||||
|  | ||||
|     mirror_log_fault_policy = "allocate" | ||||
|     mirror_image_fault_policy = "remove" | ||||
|  | ||||
|     # 'snapshot_autoextend_threshold' and 'snapshot_autoextend_percent' define | ||||
|     # how to handle automatic snapshot extension. The former defines when the | ||||
|     # snapshot should be extended: when its space usage exceeds this many | ||||
|     # percent. The latter defines how much extra space should be allocated for | ||||
|     # the snapshot, in percent of its current size. | ||||
|     # | ||||
|     # For example, if you set snapshot_autoextend_threshold to 70 and | ||||
|     # snapshot_autoextend_percent to 20, whenever a snapshot exceeds 70% usage, | ||||
|     # it will be extended by another 20%. For a 1G snapshot, using up 700M will | ||||
|     # trigger a resize to 1.2G. When the usage exceeds 840M, the snapshot will | ||||
|     # be extended to 1.44G, and so on. | ||||
|     # | ||||
|     # Setting snapshot_autoextend_threshold to 100 disables automatic | ||||
|     # extensions. The minimum value is 50 (A setting below 50 will be treated | ||||
|     # as 50). | ||||
|  | ||||
|     snapshot_autoextend_threshold = 100 | ||||
|     snapshot_autoextend_percent = 20 | ||||
|  | ||||
|     # While activating devices, I/O to devices being (re)configured is | ||||
|     # suspended, and as a precaution against deadlocks, LVM2 needs to pin | ||||
|     # any memory it is using so it is not paged out.  Groups of pages that | ||||
|     # are known not to be accessed during activation need not be pinned | ||||
|     # into memory.  Each string listed in this setting is compared against | ||||
|     # each line in /proc/self/maps, and the pages corresponding to any | ||||
|     # lines that match are not pinned.  On some systems locale-archive was | ||||
|     # found to make up over 80% of the memory used by the process. | ||||
|     # mlock_filter = [ "locale/locale-archive", "gconv/gconv-modules.cache" ] | ||||
|  | ||||
|     # Set to 1 to revert to the default behaviour prior to version 2.02.62 | ||||
|     # which used mlockall() to pin the whole process's memory while activating | ||||
|     # devices. | ||||
|     use_mlockall = 0 | ||||
|  | ||||
|     # Monitoring is enabled by default when activating logical volumes. | ||||
|     # Set to 0 to disable monitoring or use the --ignoremonitoring option. | ||||
|     monitoring = 1 | ||||
|  | ||||
|     # When pvmove or lvconvert must wait for the kernel to finish | ||||
|     # synchronising or merging data, they check and report progress | ||||
|     # at intervals of this number of seconds.  The default is 15 seconds. | ||||
|     # If this is set to 0 and there is only one thing to wait for, there | ||||
|     # are no progress reports, but the process is awoken immediately the | ||||
|     # operation is complete. | ||||
|     polling_interval = 15 | ||||
| } | ||||
|  | ||||
|  | ||||
| #################### | ||||
| # Advanced section # | ||||
| #################### | ||||
|  | ||||
| # Metadata settings | ||||
| # | ||||
| # metadata { | ||||
|     # Default number of copies of metadata to hold on each PV.  0, 1 or 2. | ||||
|     # You might want to override it from the command line with 0  | ||||
|     # when running pvcreate on new PVs which are to be added to large VGs. | ||||
|  | ||||
|     # pvmetadatacopies = 1 | ||||
|  | ||||
|     # Default number of copies of metadata to maintain for each VG. | ||||
|     # If set to a non-zero value, LVM automatically chooses which of | ||||
|     # the available metadata areas to use to achieve the requested | ||||
|     # number of copies of the VG metadata.  If you set a value larger | ||||
|     # than the the total number of metadata areas available then | ||||
|     # metadata is stored in them all. | ||||
|     # The default value of 0 ("unmanaged") disables this automatic | ||||
|     # management and allows you to control which metadata areas | ||||
|     # are used at the individual PV level using 'pvchange | ||||
|     # --metadataignore y/n'. | ||||
|  | ||||
|     # vgmetadatacopies = 0 | ||||
|  | ||||
|     # 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" ] | ||||
| #} | ||||
|  | ||||
| # Event daemon | ||||
| # | ||||
| dmeventd { | ||||
|     # mirror_library is the library used when monitoring a mirror device. | ||||
|     # | ||||
|     # "libdevmapper-event-lvm2mirror.so" attempts to recover from | ||||
|     # failures.  It removes failed devices from a volume group and | ||||
|     # reconfigures a mirror as necessary. If no mirror library is | ||||
|     # provided, mirrors are not monitored through dmeventd. | ||||
|  | ||||
|     mirror_library = "libdevmapper-event-lvm2mirror.so" | ||||
|  | ||||
|     # snapshot_library is the library used when monitoring a snapshot device. | ||||
|     # | ||||
|     # "libdevmapper-event-lvm2snapshot.so" monitors the filling of | ||||
|     # snapshots and emits a warning through syslog when the use of | ||||
|     # the snapshot exceeds 80%. The warning is repeated when 85%, 90% and | ||||
|     # 95% of the snapshot is filled. | ||||
|  | ||||
|     snapshot_library = "libdevmapper-event-lvm2snapshot.so" | ||||
|  | ||||
|     # Full path of the dmeventd binary. | ||||
|     # | ||||
|     # executable = "@DMEVENTD_PATH@" | ||||
| } | ||||
							
								
								
									
										49
									
								
								doc/example_cmdlib.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								doc/example_cmdlib.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #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) | ||||
| { | ||||
| 	/* Extract and process output here rather than printing it */ | ||||
|  | ||||
| 	if (level != 4) | ||||
| 		return; | ||||
|  | ||||
| 	printf("%s\n", format); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	void *handle; | ||||
| 	int r; | ||||
|  | ||||
| 	lvm2_log_fn(test_log_fn); | ||||
|  | ||||
| 	handle = lvm2_init(); | ||||
|  | ||||
| 	lvm2_log_level(handle, 1); | ||||
| 	r = lvm2_run(handle, "vgs --noheadings vg1"); | ||||
|  | ||||
| 	/* More commands here */ | ||||
|  | ||||
| 	lvm2_exit(handle); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
							
								
								
									
										221
									
								
								doc/lvm_fault_handling.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								doc/lvm_fault_handling.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,221 @@ | ||||
| LVM device fault handling | ||||
| ========================= | ||||
|  | ||||
| Introduction | ||||
| ------------ | ||||
| This document is to serve as the definitive source for information | ||||
| regarding the policies and procedures surrounding device failures | ||||
| in LVM.  It codifies LVM's responses to device failures as well as | ||||
| the responsibilities of administrators. | ||||
|  | ||||
| Device failures can be permanent or transient.  A permanent failure | ||||
| is one where a device becomes inaccessible and will never be | ||||
| revived.  A transient failure is a failure that can be recovered | ||||
| from (e.g. a power failure, intermittent network outage, block | ||||
| relocation, etc).  The policies for handling both types of failures | ||||
| is described herein. | ||||
|  | ||||
| Available Operations During a Device Failure | ||||
| -------------------------------------------- | ||||
| When there is a device failure, LVM behaves somewhat differently because | ||||
| only a subset of the available devices will be found for the particular | ||||
| volume group.  The number of operations available to the administrator | ||||
| is diminished.  It is not possible to create new logical volumes while | ||||
| PVs cannot be accessed, for example.  Operations that create, convert, or | ||||
| resize logical volumes are disallowed, such as: | ||||
| - lvcreate | ||||
| - lvresize | ||||
| - lvreduce | ||||
| - lvextend | ||||
| - lvconvert (unless '--repair' is used) | ||||
| Operations that activate, deactivate, remove, report, or repair logical | ||||
| volumes are allowed, such as: | ||||
| - lvremove | ||||
| - vgremove (will remove all LVs, but not the VG until consistent) | ||||
| - pvs | ||||
| - vgs | ||||
| - lvs | ||||
| - lvchange -a [yn] | ||||
| - vgchange -a [yn] | ||||
| Operations specific to the handling of failed devices are allowed and | ||||
| are as follows: | ||||
|  | ||||
| - 'vgreduce --removemissing <VG>':  This action is designed to remove | ||||
|   the reference of a failed device from the LVM metadata stored on the | ||||
|   remaining devices.  If there are (portions of) logical volumes on the | ||||
|   failed devices, the ability of the operation to proceed will depend | ||||
|   on the type of logical volumes found.  If an image (i.e leg or side) | ||||
|   of a mirror is located on the device, that image/leg of the mirror | ||||
|   is eliminated along with the failed device.  The result of such a | ||||
|   mirror reduction could be a no-longer-redundant linear device.  If | ||||
|   a linear, stripe, or snapshot device is located on the failed device | ||||
|   the command will not proceed without a '--force' option.  The result | ||||
|   of using the '--force' option is the entire removal and complete | ||||
|   loss of the non-redundant logical volume.  Once this operation is | ||||
|   complete, the volume group will again have a complete and consistent | ||||
|   view of the devices it contains.  Thus, all operations will be | ||||
|   permitted - including creation, conversion, and resizing operations. | ||||
|  | ||||
| - 'lvconvert --repair <VG/LV>':  This action is designed specifically | ||||
|   to operate on mirrored logical volumes.  It is used on logical volumes | ||||
|   individually and does not remove the faulty device from the volume | ||||
|   group.  If, for example, a failed device happened to contain the | ||||
|   images of four distinct mirrors, it would be necessary to run | ||||
|   'lvconvert --repair' on each of them.  The ultimate result is to leave | ||||
|   the faulty device in the volume group, but have no logical volumes | ||||
|   referencing it.  In addition to removing mirror images that reside | ||||
|   on failed devices, 'lvconvert --repair' can also replace the failed | ||||
|   device if there are spare devices available in the volume group.  The | ||||
|   user is prompted whether to simply remove the failed portions of the | ||||
|   mirror or to also allocate a replacement, if run from the command-line. | ||||
|   Optionally, the '--use-policies' flag can be specified which will | ||||
|   cause the operation not to prompt the user, but instead respect | ||||
|   the policies outlined in the LVM configuration file - usually, | ||||
|   /etc/lvm/lvm.conf.  Once this operation is complete, mirrored logical | ||||
|   volumes will be consistent and I/O will be allowed to continue. | ||||
|   However, the volume group will still be inconsistent -  due to the | ||||
|   refernced-but-missing device/PV - and operations will still be | ||||
|   restricted to the aformentioned actions until either the device is | ||||
|   restored or 'vgreduce --removemissing' is run. | ||||
|  | ||||
| Device Revival (transient failures): | ||||
| ------------------------------------ | ||||
| During a device failure, the above section describes what limitations | ||||
| a user can expect.  However, if the device returns after a period of | ||||
| time, what to expect will depend on what has happened during the time | ||||
| period when the device was failed.  If no automated actions (described | ||||
| below) or user actions were necessary or performed, then no change in | ||||
| operations or logical volume layout will occur.  However, if an | ||||
| automated action or one of the aforementioned repair commands was | ||||
| manually run, the returning device will be perceived as having stale | ||||
| LVM metadata.  In this case, the user can expect to see a warning | ||||
| concerning inconsistent metadata.  The metadata on the returning | ||||
| device will be automatically replaced with the latest copy of the | ||||
| LVM metadata - restoring consistency.  Note, while most LVM commands | ||||
| will automatically update the metadata on a restored devices, the | ||||
| following possible exceptions exist: | ||||
| - pvs (when it does not read/update VG metadata) | ||||
|  | ||||
| Automated Target Response to Failures: | ||||
| -------------------------------------- | ||||
| The only LVM target type (i.e. "personality") that has an automated | ||||
| response to failures is a mirrored logical volume.  The other target | ||||
| types (linear, stripe, snapshot, etc) will simply propagate the failure. | ||||
| [A snapshot becomes invalid if its underlying device fails, but the | ||||
| origin will remain valid - presuming the origin device has not failed.] | ||||
| There are three types of errors that a mirror can suffer - read, write, | ||||
| and resynchronization errors.  Each is described in depth below. | ||||
|  | ||||
| Mirror read failures: | ||||
| If a mirror is 'in-sync' (i.e. all images have been initialized and | ||||
| are identical), a read failure will only produce a warning.  Data is | ||||
| simply pulled from one of the other images and the fault is recorded. | ||||
| Sometimes - like in the case of bad block relocation - read errors can | ||||
| be recovered from by the storage hardware.  Therefore, it is up to the | ||||
| user to decide whether to reconfigure the mirror and remove the device | ||||
| that caused the error.  Managing the composition of a mirror is done with | ||||
| 'lvconvert' and removing a device from a volume group can be done with | ||||
| 'vgreduce'. | ||||
|  | ||||
| If a mirror is not 'in-sync', a read failure will produce an I/O error. | ||||
| This error will propagate all the way up to the applications above the | ||||
| logical volume (e.g. the file system).  No automatic intervention will | ||||
| take place in this case either.  It is up to the user to decide what | ||||
| can be done/salvaged in this senario.  If the user is confident that the | ||||
| images of the mirror are the same (or they are willing to simply attempt | ||||
| to retreive whatever data they can), 'lvconvert' can be used to eliminate | ||||
| the failed image and proceed. | ||||
|  | ||||
| Mirror resynchronization errors: | ||||
| A resynchronization error is one that occurs when trying to initialize | ||||
| all mirror images to be the same.  It can happen due to a failure to | ||||
| read the primary image (the image considered to have the 'good' data), or | ||||
| due to a failure to write the secondary images.  This type of failure | ||||
| only produces a warning, and it is up to the user to take action in this | ||||
| case.  If the error is transient, the user can simply reactivate the | ||||
| mirrored logical volume to make another attempt at resynchronization. | ||||
| If attempts to finish resynchronization fail, 'lvconvert' can be used to | ||||
| remove the faulty device from the mirror. | ||||
|  | ||||
| TODO... | ||||
| Some sort of response to this type of error could be automated. | ||||
| Since this document is the definitive source for how to handle device | ||||
| failures, the process should be defined here.  If the process is defined | ||||
| but not implemented, it should be noted as such.  One idea might be to | ||||
| make a single attempt to suspend/resume the mirror in an attempt to | ||||
| redo the sync operation that failed.  On the other hand, if there is | ||||
| a permanent failure, it may simply be best to wait for the user or the | ||||
| automated response that is sure to follow from a write failure. | ||||
| ...TODO | ||||
|  | ||||
| Mirror write failures: | ||||
| When a write error occurs on a mirror constituent device, an attempt | ||||
| to handle the failure is automatically made.  This is done by calling | ||||
| 'lvconvert --repair --use-policies'.  The policies implied by this | ||||
| command are set in the LVM configuration file.  They are: | ||||
| - mirror_log_fault_policy:  This defines what action should be taken | ||||
|   if the device containing the log fails.  The available options are | ||||
|   "remove" and "allocate".  Either of these options will cause the | ||||
|   faulty log device to be removed from the mirror.  The "allocate" | ||||
|   policy will attempt the further action of trying to replace the | ||||
|   failed disk log by using space that might be available in the | ||||
|   volume group.  If the allocation fails (or the "remove" policy | ||||
|   is specified), the mirror log will be maintained in memory.  Should | ||||
|   the machine be rebooted or the logical volume deactivated, a | ||||
|   complete resynchronization of the mirror will be necessary upon | ||||
|   the follow activation - such is the nature of a mirror with a 'core' | ||||
|   log.  The default policy for handling log failures is "allocate". | ||||
|   The service disruption incurred by replacing the failed log is | ||||
|   negligible, while the benefits of having persistent log is | ||||
|   pronounced. | ||||
| - mirror_image_fault_policy:  This defines what action should be taken | ||||
|   if a device containing an image fails.  Again, the available options | ||||
|   are "remove" and "allocate".  Both of these options will cause the | ||||
|   faulty image device to be removed - adjusting the logical volume | ||||
|   accordingly.  For example, if one image of a 2-way mirror fails, the | ||||
|   mirror will be converted to a linear device.  If one image of a | ||||
|   3-way mirror fails, the mirror will be converted to a 2-way mirror. | ||||
|   The "allocate" policy takes the further action of trying to replace | ||||
|   the failed image using space that is available in the volume group. | ||||
|   Replacing a failed mirror image will incure the cost of | ||||
|   resynchronizing - degrading the performance of the mirror.  The | ||||
|   default policy for handling an image failure is "remove".  This | ||||
|   allows the mirror to still function, but gives the administrator the | ||||
|   choice of when to incure the extra performance costs of replacing | ||||
|   the failed image. | ||||
|  | ||||
| TODO... | ||||
| The appropriate time to take permanent corrective action on a mirror | ||||
| should be driven by policy.  There should be a directive that takes | ||||
| a time or percentage argument.  Something like the following: | ||||
| - mirror_fault_policy_WHEN = "10sec"/"10%" | ||||
| A time value would signal the amount of time to wait for transient | ||||
| failures to resolve themselves.  The percentage value would signal the | ||||
| amount a mirror could become out-of-sync before the faulty device is | ||||
| removed. | ||||
|  | ||||
| A mirror cannot be used unless /some/ corrective action is taken, | ||||
| however.  One option is to replace the failed mirror image with an | ||||
| error target, forgo the use of 'handle_errors', and simply let the | ||||
| out-of-sync regions accumulate and be tracked by the log.  Mirrors | ||||
| that have more than 2 images would have to "stack" to perform the | ||||
| tracking, as each failed image would have to be associated with a | ||||
| log.  If the failure is transient, the device would replace the | ||||
| error target that was holding its spot and the log that was tracking | ||||
| the deltas would be used to quickly restore the portions that changed. | ||||
|  | ||||
| One unresolved issue with the above scheme is how to know which | ||||
| regions of the mirror are out-of-sync when a problem occurs.  When | ||||
| a write failure occurs in the kernel, the log will contain those | ||||
| regions that are not in-sync.  If the log is a disk log, that log | ||||
| could continue to be used to track differences.  However, if the | ||||
| log was a core log - or if the log device failed at the same time | ||||
| as an image device - there would be no way to determine which | ||||
| regions are out-of-sync to begin with as we start to track the | ||||
| deltas for the failed image.  I don't have a solution for this | ||||
| problem other than to only be able to handle errors in this way | ||||
| if conditions are right.  These issues will have to be ironed out | ||||
| before proceeding.  This could be another case, where it is better | ||||
| to handle failures in the kernel by allowing the kernel to store | ||||
| updates in various metadata areas. | ||||
| ...TODO | ||||
							
								
								
									
										52
									
								
								doc/pvmove_outline.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								doc/pvmove_outline.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| Let's say we have an LV, made up of three segments of different PV's, | ||||
| I've also added in the device major:minor as this will be useful | ||||
| later: | ||||
|  | ||||
| +-----------------------------+ | ||||
| |  PV1     |   PV2   |   PV3  | 254:3 | ||||
| +----------+---------+--------+ | ||||
|  | ||||
|  | ||||
| Now our hero decides to PV move PV2 to PV4: | ||||
|  | ||||
| 1. Suspend our LV (254:3), this starts queueing all io, and flushes | ||||
|    all pending io.  Once the suspend has completed we are free to change | ||||
|    the mapping table. | ||||
|  | ||||
| 2. Set up *another* (254:4) device with the mapping table of our LV. | ||||
|  | ||||
| 3. Load a new mapping table into (254:3) that has identity targets for | ||||
|    parts that aren't moving, and a mirror target for parts that are. | ||||
|  | ||||
| 4. Unsuspend (254:3) | ||||
|  | ||||
| So now we have: | ||||
|                            destination of copy | ||||
|                +--------------------->--------------+ | ||||
|                |                                    | | ||||
| +-----------------------------+               + -----------+ | ||||
| | Identity | mirror  | Ident. | 254:3         |    PV4     | | ||||
| +----------+---------+--------+               +------------+ | ||||
|      |         |         | | ||||
|      \/        \/        \/ | ||||
| +-----------------------------+ | ||||
| |  PV1     |   PV2   |   PV3  | 254:4 | ||||
| +----------+---------+--------+ | ||||
|  | ||||
| Any writes to segment2 of the LV get intercepted by the mirror target | ||||
| who checks that that chunk has been copied to the new destination, if | ||||
| it hasn't it queues the initial copy and defers the current io until | ||||
| it has finished.  Then the current io is written to *both* PV2 and the | ||||
| PV4. | ||||
|  | ||||
| 5. When the copying has completed 254:3 is suspended/pending flushed. | ||||
|  | ||||
| 6. 254:4 is taken down | ||||
|  | ||||
| 7. metadata is updated on disk | ||||
|  | ||||
| 8. 254:3 has new mapping table loaded: | ||||
|  | ||||
| +-----------------------------+ | ||||
| |  PV1     |   PV4   |   PV3  | 254:3 | ||||
| +----------+---------+--------+ | ||||
							
								
								
									
										165
									
								
								doc/tagging.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								doc/tagging.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | ||||
| Tagging aims | ||||
| ============ | ||||
|   1) Ability to attach an unordered list of tags to LVM metadata objects. | ||||
|   2) Ability to add or remove tags easily. | ||||
|   3) Ability to select LVM objects for processing according to presence/absence | ||||
|      of specific tags. | ||||
|   4) Ability to control through the config file which VGs/LVs are activated  | ||||
|      on different machines using names or tags. | ||||
|   5) Ability to overlay settings from different config files e.g. override | ||||
|      some settings in a global config file locally. | ||||
|  | ||||
| Clarifications | ||||
| ============== | ||||
|   1) Tag character set: A-Za-z0-9_+.-  | ||||
|      Can't start with hyphen & max length is 128 (NAME_LEN). | ||||
|   2) LVM object types that can be tagged: | ||||
|        VG, LV, LV segment | ||||
|        PV - tags are stored in VG metadata so disappear when PV becomes orphaned | ||||
|      Snapshots can't be tagged, but their origin may be. | ||||
|   3) A tag can be used in place of any command line LVM object reference that | ||||
|      accepts (a) a list of objects; or (b) a single object as long as the | ||||
|      tag expands to a single object.  This is not supported everywhere yet. | ||||
|      Duplicate arguments in a list after argument expansion may get removed  | ||||
|      retaining the first copy of each argument. | ||||
|   4) Wherever there may be ambiguity of argument type, a tag must be prefixed  | ||||
|      by '@'; elsewhere an '@' prefix is optional. | ||||
|   5) LVM1 objects cannot be tagged, as the disk format doesn't support it. | ||||
|   6) Tags can be added or removed with --addtag or --deltag. | ||||
|  | ||||
| Config file Extensions | ||||
| ====================== | ||||
|   To define host tags in config file: | ||||
|  | ||||
|   tags { | ||||
|   	# Set a tag with the hostname | ||||
| 	hosttags = 1 | ||||
|  | ||||
| 	tag1 { } | ||||
|  | ||||
|   	tag2 { | ||||
| 		# If no exact match, tag is not set. | ||||
| 		host_list = [ "hostname", "dbase" ] | ||||
| 	} | ||||
|   } | ||||
|  | ||||
| Activation config file example | ||||
| ============================== | ||||
|   activation { | ||||
|       volume_list = [ "vg1/lvol0", "@database" ] | ||||
|   } | ||||
|  | ||||
|   Matches against vgname, vgname/lvname or @tag set in *metadata*. | ||||
|   @* matches exactly against *any* tag set on the host. | ||||
|   The VG or LV only gets activated if a metadata tag matches. | ||||
|   The default if there is no match is not to activate. | ||||
|   If volume_list is not present and any tags are defined on the host  | ||||
|   then it only activates if a host tag matches a metadata tag. | ||||
|   If volume_list is not present and no tags are defined on the host  | ||||
|   then it does activate. | ||||
|  | ||||
| Multiple config files | ||||
| ===================== | ||||
|   (a) lvm.conf | ||||
|   (b) lvm_<host_tag>.conf | ||||
|  | ||||
|   At startup, load lvm.conf. | ||||
|   Process tag settings. | ||||
|   If any host tags were defined, load lvm_tag.conf for each tag, if present. | ||||
|  | ||||
|   When searching for a specific config file entry, search order is (b) | ||||
|   then (a), stopping at the first match.   | ||||
|   Within (b) use reverse order tags got set, so file for last tag set is | ||||
|   searched first. | ||||
|   New tags set in (b) *do* trigger additional config file loads.  | ||||
|  | ||||
| Usage Examples | ||||
| ============== | ||||
|   1) Simple activation control via metadata with static config files | ||||
|  | ||||
|   lvm.conf:  (Identical on every machine - global settings) | ||||
|     tags { | ||||
|       hostname_tags = 1 | ||||
|     } | ||||
|  | ||||
|   From any machine in the cluster, add db1 to the list of machines that | ||||
|   activate vg1/lvol2: | ||||
|  | ||||
|   lvchange --tag @db1 vg1/lvol2 | ||||
|   (followed by lvchange -ay to actually activate it) | ||||
|  | ||||
|  | ||||
|   2) Multiple hosts.   | ||||
|  | ||||
|     Activate vg1 only on the database hosts, db1 and db2. | ||||
|     Activate vg2 only on the fileserver host fs1. | ||||
|     Activate nothing initially on the fileserver backup host fsb1, but be | ||||
|     prepared for it to take over from fs1. | ||||
|  | ||||
|   Option (i) - centralised admin, static configuration replicated between hosts   | ||||
|     # Add @database tag to vg1's metadata | ||||
|     vgchange --tag @database vg1 | ||||
|  | ||||
|     # Add @fileserver tag to vg2's metadata | ||||
|     vgchange --tag @fileserver vg2 | ||||
|  | ||||
|     lvm.conf:  (Identical on every machine) | ||||
|       tags { | ||||
|         database { | ||||
|           host_list = [ "db1", "db2" ] | ||||
|         } | ||||
|         fileserver { | ||||
| 	  host_list = [ "fs1" ] | ||||
|         } | ||||
|         fileserverbackup { | ||||
|           host_list = [ "fsb1" ] | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       activation { | ||||
|         # Only activate if host has a tag that matches a metadata tag | ||||
|         volume_list = [ "@*" ] | ||||
|       } | ||||
|    | ||||
|   In the event of the fileserver host going down, vg2 can be brought up | ||||
|   on fsb1 by running *on any node* 'vgchange --tag @fileserverbackup vg2' | ||||
|   followed by 'vgchange -ay vg2' | ||||
|    | ||||
|    | ||||
|   Option (ii) - localised admin & configuation | ||||
|   (i.e. each host holds *locally* which classes of volumes to activate) | ||||
|     # Add @database tag to vg1's metadata | ||||
|     vgchange --tag @database vg1 | ||||
|    | ||||
|     # Add @fileserver tag to vg2's metadata | ||||
|     vgchange --tag @fileserver vg2 | ||||
|    | ||||
|     lvm.conf:  (Identical on every machine - global settings) | ||||
|       tags { | ||||
|         hosttags = 1 | ||||
|       } | ||||
|    | ||||
|     lvm_db1.conf: (only needs to be on db1 - could be symlink to lvm_db.conf) | ||||
|       activation { | ||||
|         volume_list = [ "@database" ] | ||||
|       } | ||||
|    | ||||
|     lvm_db2.conf: (only needs to be on db2 - could be symlink to lvm_db.conf) | ||||
|       activation { | ||||
|         volume_list = [ "@database" ] | ||||
|       } | ||||
|    | ||||
|     lvm_fs1.conf: (only needs to be on fs1 - could be symlink to lvm_fs.conf) | ||||
|       activation { | ||||
|         volume_list = [ "@fileserver" ] | ||||
|       } | ||||
|    | ||||
|     If fileserver goes down, to bring a spare machine fsb1 in as fileserver, | ||||
|     create lvm_fsb1.conf on fsb1 (or symlink to lvm_fs.conf): | ||||
|  | ||||
|       activation { | ||||
|         volume_list = [ "@fileserver" ] | ||||
|       } | ||||
|  | ||||
|     and run 'vgchange -ay vg2' or 'vgchange -ay @fileserver' | ||||
|  | ||||
							
								
								
									
										41
									
								
								doc/testing.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								doc/testing.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| Here's how I test new LVM2 builds without interfering with the stable | ||||
| LVM2 that is running the LV's on my development box. | ||||
|  | ||||
| 1) Create a set of loopback devices. | ||||
|  | ||||
| 2) Create a new directory to contain the LVM2 configuration files for | ||||
|    this setup.  (I use /etc/lvm_loops) | ||||
|  | ||||
| 3) Write a suitable lvm.conf file, this goes in the directory you just | ||||
|    created.  eg, my /etc/lvm_loops/lvm.conf looks like: | ||||
|  | ||||
|    log { | ||||
|         file="/tmp/lvm2_loop.log" | ||||
|         level=9 | ||||
|         verbose=0 | ||||
|         overwrite=1 | ||||
|    } | ||||
|  | ||||
|    devices { | ||||
|         scan = "/dev" | ||||
|         filter = ["a/loop/", "r/.*/"] | ||||
|    } | ||||
|  | ||||
|  | ||||
|    The important thing to note is the devices section which makes sure | ||||
|    that only the loopback devices are considered for LVM2 operations. | ||||
|  | ||||
| 4) When you want to use this test setup just set the environment | ||||
|    variable LVM_SYSTEM_DIR to point to your config directory | ||||
|    (/etc/lvm_loops in my case). | ||||
|  | ||||
| 5) It's a good idea to do a vgscan to initialise the filters: | ||||
|  | ||||
|    export LVM_SYSTEM_DIR=/etc/lvm_loops | ||||
|    ./lvm vgscan | ||||
|  | ||||
|    where ./lvm is the new build of LVM2 that I'm trying out. | ||||
|  | ||||
| 7) Test away.  Make sure that you are explicit about which lvm | ||||
|    executable you want to execute (eg, ./lvm if you are in | ||||
|    LVM2/tools). | ||||
| @@ -1 +0,0 @@ | ||||
| The driver directory | ||||
							
								
								
									
										67
									
								
								include/.symlinks.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								include/.symlinks.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| @top_srcdir@/daemons/clvmd/clvm.h | ||||
| @top_srcdir@/daemons/dmeventd/libdevmapper-event.h | ||||
| @top_srcdir@/liblvm/lvm2app.h | ||||
| @top_srcdir@/lib/activate/activate.h | ||||
| @top_srcdir@/lib/activate/targets.h | ||||
| @top_srcdir@/lib/cache/lvmcache.h | ||||
| @top_srcdir@/lib/commands/errors.h | ||||
| @top_srcdir@/lib/commands/toolcontext.h | ||||
| @top_srcdir@/lib/config/config.h | ||||
| @top_srcdir@/lib/config/defaults.h | ||||
| @top_srcdir@/lib/datastruct/btree.h | ||||
| @top_srcdir@/lib/datastruct/lvm-types.h | ||||
| @top_srcdir@/lib/datastruct/str_list.h | ||||
| @top_srcdir@/lib/device/dev-cache.h | ||||
| @top_srcdir@/lib/device/device.h | ||||
| @top_srcdir@/lib/display/display.h | ||||
| @top_srcdir@/lib/filters/filter-composite.h | ||||
| @top_srcdir@/lib/filters/filter-md.h | ||||
| @top_srcdir@/lib/filters/filter-persistent.h | ||||
| @top_srcdir@/lib/filters/filter-regex.h | ||||
| @top_srcdir@/lib/filters/filter-sysfs.h | ||||
| @top_srcdir@/lib/filters/filter.h | ||||
| @top_srcdir@/lib/format1/format1.h | ||||
| @top_srcdir@/lib/format_pool/format_pool.h | ||||
| @top_srcdir@/lib/format_text/archiver.h | ||||
| @top_srcdir@/lib/format_text/format-text.h | ||||
| @top_srcdir@/lib/format_text/text_export.h | ||||
| @top_srcdir@/lib/format_text/text_import.h | ||||
| @top_srcdir@/lib/label/label.h | ||||
| @top_srcdir@/lib/locking/locking.h | ||||
| @top_srcdir@/lib/log/log.h | ||||
| @top_srcdir@/lib/log/lvm-logging.h | ||||
| @top_srcdir@/lib/metadata/lv.h | ||||
| @top_srcdir@/lib/metadata/lv_alloc.h | ||||
| @top_srcdir@/lib/metadata/metadata.h | ||||
| @top_srcdir@/lib/metadata/metadata-exported.h | ||||
| @top_srcdir@/lib/metadata/pv.h | ||||
| @top_srcdir@/lib/metadata/pv_alloc.h | ||||
| @top_srcdir@/lib/metadata/segtype.h | ||||
| @top_srcdir@/lib/metadata/vg.h | ||||
| @top_srcdir@/lib/mm/memlock.h | ||||
| @top_srcdir@/lib/mm/xlate.h | ||||
| @top_builddir@/lib/misc/configure.h | ||||
| @top_srcdir@/lib/misc/crc.h | ||||
| @top_srcdir@/lib/misc/intl.h | ||||
| @top_srcdir@/lib/misc/util.h | ||||
| @top_srcdir@/lib/misc/last-path-component.h | ||||
| @top_srcdir@/lib/misc/lib.h | ||||
| @top_srcdir@/lib/misc/lvm-exec.h | ||||
| @top_srcdir@/lib/misc/lvm-file.h | ||||
| @top_srcdir@/lib/misc/lvm-globals.h | ||||
| @top_srcdir@/lib/misc/lvm-string.h | ||||
| @top_builddir@/lib/misc/lvm-version.h | ||||
| @top_srcdir@/lib/misc/lvm-wrappers.h | ||||
| @top_srcdir@/lib/misc/lvm-percent.h | ||||
| @top_srcdir@/lib/misc/sharedlib.h | ||||
| @top_srcdir@/lib/report/properties.h | ||||
| @top_srcdir@/lib/report/report.h | ||||
| @top_srcdir@/lib/uuid/uuid.h | ||||
| @top_srcdir@/libdm/libdevmapper.h | ||||
| @top_srcdir@/libdm/misc/dm-ioctl.h | ||||
| @top_srcdir@/libdm/misc/dm-logging.h | ||||
| @top_srcdir@/libdm/misc/dm-log-userspace.h | ||||
| @top_srcdir@/libdm/misc/dmlib.h | ||||
| @top_srcdir@/libdm/misc/kdev_t.h | ||||
| @top_srcdir@/po/pogen.h | ||||
| @top_srcdir@/tools/lvm2cmd.h | ||||
							
								
								
									
										35
									
								
								include/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								include/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| # | ||||
| # Copyright (C) 2001-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 | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| all: .symlinks_created | ||||
|  | ||||
| .symlinks_created: .symlinks  | ||||
| 	find . -maxdepth 1 -type l -exec $(RM) \{\} \; | ||||
| 	for i in `cat $<`; do $(LN_S) $$i ; done | ||||
| 	touch $@ | ||||
|  | ||||
| pofile: all | ||||
|  | ||||
| device-mapper: all | ||||
|  | ||||
| cflow: all | ||||
|  | ||||
| DISTCLEAN_TARGETS += $(shell find . -maxdepth 1 -type l) | ||||
| DISTCLEAN_TARGETS += .include_symlinks .symlinks_created .symlinks | ||||
							
								
								
									
										184
									
								
								lib/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								lib/Makefile.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| # | ||||
| # Copyright (C) 2001-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 | ||||
|  | ||||
| srcdir = @srcdir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| top_builddir = @top_builddir@ | ||||
|  | ||||
| ifeq ("@LVM1@", "shared") | ||||
|   SUBDIRS = format1 | ||||
| endif | ||||
|  | ||||
| ifeq ("@POOL@", "shared") | ||||
|   SUBDIRS += format_pool | ||||
| endif | ||||
|  | ||||
| ifeq ("@SNAPSHOTS@", "shared") | ||||
|   SUBDIRS += snapshot | ||||
| endif | ||||
|  | ||||
| ifeq ("@MIRRORS@", "shared") | ||||
|   SUBDIRS += mirror | ||||
| endif | ||||
|  | ||||
| ifeq ("@REPLICATORS@", "shared") | ||||
|   SUBDIRS += replicator | ||||
| endif | ||||
|  | ||||
| SOURCES =\ | ||||
| 	activate/activate.c \ | ||||
| 	cache/lvmcache.c \ | ||||
| 	commands/toolcontext.c \ | ||||
| 	config/config.c \ | ||||
| 	datastruct/btree.c \ | ||||
| 	datastruct/str_list.c \ | ||||
| 	device/dev-cache.c \ | ||||
| 	device/dev-io.c \ | ||||
| 	device/dev-md.c \ | ||||
| 	device/dev-swap.c \ | ||||
| 	device/dev-luks.c \ | ||||
| 	device/device.c \ | ||||
| 	display/display.c \ | ||||
| 	error/errseg.c \ | ||||
| 	unknown/unknown.c \ | ||||
| 	filters/filter-composite.c \ | ||||
| 	filters/filter-persistent.c \ | ||||
| 	filters/filter-regex.c \ | ||||
| 	filters/filter-sysfs.c \ | ||||
| 	filters/filter-md.c \ | ||||
| 	filters/filter.c \ | ||||
| 	format_text/archive.c \ | ||||
| 	format_text/archiver.c \ | ||||
| 	format_text/export.c \ | ||||
| 	format_text/flags.c \ | ||||
| 	format_text/format-text.c \ | ||||
| 	format_text/import.c \ | ||||
| 	format_text/import_vsn1.c \ | ||||
| 	format_text/tags.c \ | ||||
| 	format_text/text_label.c \ | ||||
| 	freeseg/freeseg.c \ | ||||
| 	label/label.c \ | ||||
| 	locking/file_locking.c \ | ||||
| 	locking/locking.c \ | ||||
| 	locking/no_locking.c \ | ||||
| 	log/log.c \ | ||||
| 	metadata/lv.c \ | ||||
| 	metadata/lv_manip.c \ | ||||
| 	metadata/merge.c \ | ||||
| 	metadata/metadata.c \ | ||||
| 	metadata/mirror.c \ | ||||
| 	metadata/pv.c \ | ||||
| 	metadata/pv_manip.c \ | ||||
| 	metadata/pv_map.c \ | ||||
| 	metadata/replicator_manip.c \ | ||||
| 	metadata/segtype.c \ | ||||
| 	metadata/snapshot_manip.c \ | ||||
| 	metadata/vg.c \ | ||||
| 	misc/crc.c \ | ||||
| 	misc/lvm-exec.c \ | ||||
| 	misc/lvm-file.c \ | ||||
| 	misc/lvm-globals.c \ | ||||
| 	misc/lvm-string.c \ | ||||
| 	misc/lvm-wrappers.c \ | ||||
| 	misc/lvm-percent.c \ | ||||
| 	misc/util.c \ | ||||
| 	mm/memlock.c \ | ||||
| 	report/properties.c \ | ||||
| 	report/report.c \ | ||||
| 	striped/striped.c \ | ||||
| 	uuid/uuid.c \ | ||||
| 	zero/zero.c | ||||
|  | ||||
| ifeq ("@HAVE_REALTIME@", "yes") | ||||
|   SOURCES +=\ | ||||
| 	misc/timestamp.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@LVM1@", "internal") | ||||
|   SOURCES +=\ | ||||
| 	format1/disk-rep.c \ | ||||
| 	format1/format1.c \ | ||||
| 	format1/import-export.c \ | ||||
| 	format1/import-extents.c \ | ||||
| 	format1/layout.c \ | ||||
| 	format1/lvm1-label.c \ | ||||
| 	format1/vg_number.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@POOL@", "internal") | ||||
|   SOURCES +=\ | ||||
| 	format_pool/disk_rep.c \ | ||||
| 	format_pool/format_pool.c \ | ||||
| 	format_pool/import_export.c \ | ||||
| 	format_pool/pool_label.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLUSTER@", "internal") | ||||
|   SOURCES += locking/cluster_locking.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@CLUSTER@", "shared") | ||||
|   SUBDIRS += locking | ||||
| endif | ||||
|  | ||||
| ifeq ("@SNAPSHOTS@", "internal") | ||||
|   SOURCES += snapshot/snapshot.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@MIRRORS@", "internal") | ||||
|   SOURCES += mirror/mirrored.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@REPLICATORS@", "internal") | ||||
|   SOURCES += replicator/replicator.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@DEVMAPPER@", "yes") | ||||
|   SOURCES +=\ | ||||
| 	activate/dev_manager.c \ | ||||
| 	activate/fs.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@HAVE_LIBDL@", "yes") | ||||
|   SOURCES +=\ | ||||
| 	locking/external_locking.c \ | ||||
| 	misc/sharedlib.c | ||||
| endif | ||||
|  | ||||
| ifeq ("@DMEVENTD@", "yes") | ||||
|   CLDFLAGS += -L$(top_builddir)/daemons/dmeventd | ||||
|   LIBS += -ldevmapper-event | ||||
| endif | ||||
|  | ||||
| LIB_NAME = liblvm-internal | ||||
| LIB_STATIC = $(LIB_NAME).a | ||||
|  | ||||
| ifeq ($(MAKECMDGOALS),distclean) | ||||
|   SUBDIRS =\ | ||||
| 	format1 \ | ||||
| 	format_pool \ | ||||
| 	snapshot \ | ||||
| 	mirror \ | ||||
| 	replicator \ | ||||
| 	locking | ||||
| endif | ||||
|  | ||||
| CFLOW_LIST = $(SOURCES) | ||||
| CFLOW_LIST_TARGET = $(LIB_NAME).cflow | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| $(SUBDIRS): $(LIB_STATIC) | ||||
|  | ||||
| DISTCLEAN_TARGETS += misc/configure.h misc/lvm-version.h | ||||
| @@ -1 +0,0 @@ | ||||
| Base library directory | ||||
							
								
								
									
										1383
									
								
								lib/activate/activate.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1383
									
								
								lib/activate/activate.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										129
									
								
								lib/activate/activate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								lib/activate/activate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-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 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_ACTIVATE_H | ||||
| #define LVM_ACTIVATE_H | ||||
|  | ||||
| #include "metadata-exported.h" | ||||
|  | ||||
| struct lvinfo { | ||||
| 	int exists; | ||||
| 	int suspended; | ||||
| 	unsigned int open_count; | ||||
| 	int major; | ||||
| 	int minor; | ||||
| 	int read_only; | ||||
| 	int live_table; | ||||
| 	int inactive_table; | ||||
| 	uint32_t read_ahead; | ||||
| }; | ||||
|  | ||||
| /* target attribute flags */ | ||||
| #define MIRROR_LOG_CLUSTERED	0x00000001U | ||||
|  | ||||
| void set_activation(int activation); | ||||
| int activation(void); | ||||
|  | ||||
| int driver_version(char *version, size_t size); | ||||
| int library_version(char *version, size_t size); | ||||
| int lvm1_present(struct cmd_context *cmd); | ||||
|  | ||||
| int module_present(struct cmd_context *cmd, const char *target_name); | ||||
| int target_present(struct cmd_context *cmd, const char *target_name, | ||||
| 		   int use_modprobe); | ||||
| int target_version(const char *target_name, uint32_t *maj, | ||||
| 		   uint32_t *min, uint32_t *patchlevel); | ||||
| int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg, | ||||
| 			 struct dm_list *modules); | ||||
| int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv, | ||||
| 		    struct dm_list *modules); | ||||
|  | ||||
| void activation_release(void); | ||||
| void activation_exit(void); | ||||
|  | ||||
| /* int lv_suspend(struct cmd_context *cmd, const char *lvid_s); */ | ||||
| int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only); | ||||
| int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only); | ||||
| int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only); | ||||
| int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive); | ||||
| int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, | ||||
| 			    int exclusive); | ||||
| int lv_deactivate(struct cmd_context *cmd, const char *lvid_s); | ||||
|  | ||||
| int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv); | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if info structure has been populated, else 0. | ||||
|  */ | ||||
| int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, | ||||
| 	    unsigned origin_only, struct lvinfo *info, | ||||
| 	    int with_open_count, int with_read_ahead); | ||||
| int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, | ||||
| 		    struct lvinfo *info, int with_open_count, int with_read_ahead); | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if activate_lv has been set: 1 = activate; 0 = don't. | ||||
|  */ | ||||
| int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s, | ||||
| 			 int *activate_lv); | ||||
|  | ||||
| int lv_check_transient(struct logical_volume *lv); | ||||
| /* | ||||
|  * Returns 1 if percent has been set, else 0. | ||||
|  */ | ||||
| int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent); | ||||
| int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, | ||||
| 		      int wait, percent_t *percent, uint32_t *event_nr); | ||||
|  | ||||
| /* | ||||
|  * Return number of LVs in the VG that are active. | ||||
|  */ | ||||
| int lvs_in_vg_activated(struct volume_group *vg); | ||||
| int lvs_in_vg_opened(const struct volume_group *vg); | ||||
|  | ||||
| int lv_is_active(struct logical_volume *lv); | ||||
|  | ||||
| int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv, | ||||
| 		       const char *layer, const char *target_type); | ||||
|  | ||||
| int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv, | ||||
| 			   unsigned origin_only, int do_reg); | ||||
|  | ||||
| #ifdef DMEVENTD | ||||
| #  include "libdevmapper-event.h" | ||||
| char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath); | ||||
| int target_registered_with_dmeventd(struct cmd_context *cmd, const char *libpath, | ||||
| 				    struct logical_volume *lv, int *pending); | ||||
| int target_register_events(struct cmd_context *cmd, const char *dso, struct logical_volume *lv, | ||||
| 			    int evmask __attribute__((unused)), int set, int timeout); | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if PV has a dependency tree that uses anything in VG. | ||||
|  */ | ||||
| int pv_uses_vg(struct physical_volume *pv, | ||||
| 	       struct volume_group *vg); | ||||
|  | ||||
| /* | ||||
|  * Returns 1 if mapped device is not suspended. | ||||
|  */ | ||||
| int device_is_usable(struct device *dev); | ||||
|  | ||||
| /* | ||||
|  * Declaration moved here from fs.h to keep header fs.h hidden | ||||
|  */ | ||||
| void fs_unlock(void); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1820
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1820
									
								
								lib/activate/dev_manager.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										71
									
								
								lib/activate/dev_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								lib/activate/dev_manager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2006 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DEV_MANAGER_H | ||||
| #define _LVM_DEV_MANAGER_H | ||||
|  | ||||
| #include "metadata-exported.h" | ||||
|  | ||||
| struct logical_volume; | ||||
| struct volume_group; | ||||
| struct cmd_context; | ||||
| struct dev_manager; | ||||
| struct dm_info; | ||||
| struct device; | ||||
|  | ||||
| /* | ||||
|  * Constructor and destructor. | ||||
|  */ | ||||
| struct dev_manager *dev_manager_create(struct cmd_context *cmd, | ||||
| 				       const char *vg_name); | ||||
| void dev_manager_destroy(struct dev_manager *dm); | ||||
| void dev_manager_release(void); | ||||
| void dev_manager_exit(void); | ||||
|  | ||||
| /* | ||||
|  * The device handler is responsible for creating all the layered | ||||
|  * dm devices, and ensuring that all constraints are maintained | ||||
|  * (eg, an origin is created before its snapshot, but is not | ||||
|  * unsuspended until the snapshot is also created.) | ||||
|  */ | ||||
| int dev_manager_info(struct dm_pool *mem, const struct logical_volume *lv, | ||||
| 		     const char *layer, | ||||
| 		     int with_open_count, int with_read_ahead, | ||||
| 		     struct dm_info *info, uint32_t *read_ahead); | ||||
| int dev_manager_snapshot_percent(struct dev_manager *dm, | ||||
| 				 const struct logical_volume *lv, | ||||
| 				 percent_t *percent); | ||||
| int dev_manager_mirror_percent(struct dev_manager *dm, | ||||
| 			       const struct logical_volume *lv, int wait, | ||||
| 			       percent_t *percent, uint32_t *event_nr); | ||||
| int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv, | ||||
| 			unsigned origin_only, int lockfs, int flush_required); | ||||
| int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv, unsigned origin_only); | ||||
| int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv, | ||||
| 			unsigned origin_only, int *flush_required); | ||||
| int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv); | ||||
| int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv) __attribute__((nonnull(1, 2))); | ||||
|  | ||||
| int dev_manager_mknodes(const struct logical_volume *lv); | ||||
|  | ||||
| /* | ||||
|  * Put the desired changes into effect. | ||||
|  */ | ||||
| int dev_manager_execute(struct dev_manager *dm); | ||||
|  | ||||
| int dev_manager_device_uses_vg(struct device *dev, | ||||
| 			       struct volume_group *vg); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										424
									
								
								lib/activate/fs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								lib/activate/fs.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,424 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-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 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 "fs.h" | ||||
| #include "activate.h" | ||||
| #include "toolcontext.h" | ||||
| #include "lvm-string.h" | ||||
| #include "lvm-file.h" | ||||
| #include "memlock.h" | ||||
|  | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <limits.h> | ||||
| #include <dirent.h> | ||||
|  | ||||
| /* | ||||
|  * Library cookie to combine multiple fs transactions. | ||||
|  * Supports to wait for udev device settle only when needed. | ||||
|  */ | ||||
| static uint32_t _fs_cookie = DM_COOKIE_AUTO_CREATE; | ||||
|  | ||||
| static int _mk_dir(const char *dev_dir, const char *vg_name) | ||||
| { | ||||
| 	char vg_path[PATH_MAX]; | ||||
| 	mode_t old_umask; | ||||
|  | ||||
| 	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s", | ||||
| 			 dev_dir, vg_name) == -1) { | ||||
| 		log_error("Couldn't construct name of volume " | ||||
| 			  "group directory."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dir_exists(vg_path)) | ||||
| 		return 1; | ||||
|  | ||||
| 	log_very_verbose("Creating directory %s", vg_path); | ||||
|  | ||||
| 	(void) dm_prepare_selinux_context(vg_path, S_IFDIR); | ||||
| 	old_umask = umask(DM_DEV_DIR_UMASK); | ||||
| 	if (mkdir(vg_path, 0777)) { | ||||
| 		log_sys_error("mkdir", vg_path); | ||||
| 		umask(old_umask); | ||||
| 		(void) dm_prepare_selinux_context(NULL, 0); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	umask(old_umask); | ||||
| 	(void) dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _rm_dir(const char *dev_dir, const char *vg_name) | ||||
| { | ||||
| 	char vg_path[PATH_MAX]; | ||||
|  | ||||
| 	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s", | ||||
| 			 dev_dir, vg_name) == -1) { | ||||
| 		log_error("Couldn't construct name of volume " | ||||
| 			  "group directory."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dir_exists(vg_path) && is_empty_dir(vg_path)) { | ||||
| 		log_very_verbose("Removing directory %s", vg_path); | ||||
| 		rmdir(vg_path); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _rm_blks(const char *dir) | ||||
| { | ||||
| 	const char *name; | ||||
| 	char path[PATH_MAX]; | ||||
| 	struct dirent *dirent; | ||||
| 	struct stat buf; | ||||
| 	DIR *d; | ||||
|  | ||||
| 	if (!(d = opendir(dir))) { | ||||
| 		log_sys_error("opendir", dir); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	while ((dirent = readdir(d))) { | ||||
| 		name = dirent->d_name; | ||||
|  | ||||
| 		if (!strcmp(name, ".") || !strcmp(name, "..")) | ||||
| 			continue; | ||||
|  | ||||
| 		if (dm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) { | ||||
| 			log_error("Couldn't create path for %s", name); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!lstat(path, &buf)) { | ||||
| 			if (!S_ISBLK(buf.st_mode)) | ||||
| 				continue; | ||||
| 			log_very_verbose("Removing %s", path); | ||||
| 			if (unlink(path) < 0) | ||||
| 				log_sys_error("unlink", path); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (closedir(d)) | ||||
| 		log_sys_error("closedir", dir); | ||||
| } | ||||
|  | ||||
| static int _mk_link(const char *dev_dir, const char *vg_name, | ||||
| 		    const char *lv_name, const char *dev, int check_udev) | ||||
| { | ||||
| 	char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX]; | ||||
| 	char vg_path[PATH_MAX]; | ||||
| 	struct stat buf, buf_lp; | ||||
|  | ||||
| 	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s", | ||||
| 			 dev_dir, vg_name) == -1) { | ||||
| 		log_error("Couldn't create path for volume group dir %s", | ||||
| 			  vg_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path, | ||||
| 			 lv_name) == -1) { | ||||
| 		log_error("Couldn't create source pathname for " | ||||
| 			  "logical volume link %s", lv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dm_snprintf(link_path, sizeof(link_path), "%s/%s", | ||||
| 			 dm_dir(), dev) == -1) { | ||||
| 		log_error("Couldn't create destination pathname for " | ||||
| 			  "logical volume link for %s", lv_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (dm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group", | ||||
| 			 vg_path) == -1) { | ||||
| 		log_error("Couldn't create pathname for LVM1 group file for %s", | ||||
| 			  vg_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* To reach this point, the VG must have been locked. | ||||
| 	 * As locking fails if the VG is active under LVM1, it's | ||||
| 	 * now safe to remove any LVM1 devices we find here | ||||
| 	 * (as well as any existing LVM2 symlink). */ | ||||
| 	if (!lstat(lvm1_group_path, &buf)) { | ||||
| 		if (!S_ISCHR(buf.st_mode)) { | ||||
| 			log_error("Non-LVM1 character device found at %s", | ||||
| 				  lvm1_group_path); | ||||
| 		} else { | ||||
| 			_rm_blks(vg_path); | ||||
|  | ||||
| 			log_very_verbose("Removing %s", lvm1_group_path); | ||||
| 			if (unlink(lvm1_group_path) < 0) | ||||
| 				log_sys_error("unlink", lvm1_group_path); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!lstat(lv_path, &buf)) { | ||||
| 		if (!S_ISLNK(buf.st_mode) && !S_ISBLK(buf.st_mode)) { | ||||
| 			log_error("Symbolic link %s not created: file exists", | ||||
| 				  link_path); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		if (dm_udev_get_sync_support() && udev_checking() && check_udev) { | ||||
| 			/* Check udev created the correct link. */ | ||||
| 			if (!stat(link_path, &buf_lp) && | ||||
| 			    !stat(lv_path, &buf)) { | ||||
| 				if (buf_lp.st_rdev == buf.st_rdev) | ||||
| 					return 1; | ||||
| 				else | ||||
| 					log_warn("Symlink %s that should have been " | ||||
| 						 "created by udev does not have " | ||||
| 						 "correct target. Falling back to " | ||||
| 						 "direct link creation", lv_path); | ||||
| 			} else | ||||
| 				log_warn("Symlink %s that should have been " | ||||
| 					 "created by udev could not be checked " | ||||
| 					 "for its correctness. Falling back to " | ||||
| 					 "direct link creation.", lv_path); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		log_very_verbose("Removing %s", lv_path); | ||||
| 		if (unlink(lv_path) < 0) { | ||||
| 			log_sys_error("unlink", lv_path); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} else if (dm_udev_get_sync_support() && udev_checking() && check_udev) | ||||
| 		log_warn("The link %s should had been created by udev " | ||||
| 			  "but it was not found. Falling back to " | ||||
| 			  "direct link creation.", lv_path); | ||||
|  | ||||
| 	log_very_verbose("Linking %s -> %s", lv_path, link_path); | ||||
|  | ||||
| 	(void) dm_prepare_selinux_context(lv_path, S_IFLNK); | ||||
| 	if (symlink(link_path, lv_path) < 0) { | ||||
| 		log_sys_error("symlink", lv_path); | ||||
| 		(void) dm_prepare_selinux_context(NULL, 0); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	(void) dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _rm_link(const char *dev_dir, const char *vg_name, | ||||
| 		    const char *lv_name, int check_udev) | ||||
| { | ||||
| 	struct stat buf; | ||||
| 	char lv_path[PATH_MAX]; | ||||
|  | ||||
| 	if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s", | ||||
| 			 dev_dir, vg_name, lv_name) == -1) { | ||||
| 		log_error("Couldn't determine link pathname."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (lstat(lv_path, &buf) && errno == ENOENT) | ||||
| 		return 1; | ||||
| 	else if (dm_udev_get_sync_support() && udev_checking() && check_udev) | ||||
| 		log_warn("The link %s should have been removed by udev " | ||||
| 			 "but it is still present. Falling back to " | ||||
| 			 "direct link removal.", lv_path); | ||||
|  | ||||
| 	if (!S_ISLNK(buf.st_mode)) { | ||||
| 		log_error("%s not symbolic link - not removing", lv_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	log_very_verbose("Removing link %s", lv_path); | ||||
| 	if (unlink(lv_path) < 0) { | ||||
| 		log_sys_error("unlink", lv_path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| typedef enum { | ||||
| 	FS_ADD, | ||||
| 	FS_DEL, | ||||
| 	FS_RENAME | ||||
| } fs_op_t; | ||||
|  | ||||
| static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, | ||||
| 		     const char *lv_name, const char *dev, | ||||
| 		     const char *old_lv_name, int check_udev) | ||||
| { | ||||
| 	switch (type) { | ||||
| 	case FS_ADD: | ||||
| 		if (!_mk_dir(dev_dir, vg_name) || | ||||
| 		    !_mk_link(dev_dir, vg_name, lv_name, dev, check_udev)) | ||||
| 			return_0; | ||||
| 		break; | ||||
| 	case FS_DEL: | ||||
| 		if (!_rm_link(dev_dir, vg_name, lv_name, check_udev) || | ||||
| 		    !_rm_dir(dev_dir, vg_name)) | ||||
| 			return_0; | ||||
| 		break; | ||||
| 		/* FIXME Use rename() */ | ||||
| 	case FS_RENAME: | ||||
| 		if (old_lv_name && !_rm_link(dev_dir, vg_name, old_lv_name, | ||||
| 					     check_udev)) | ||||
| 			stack; | ||||
|  | ||||
| 		if (!_mk_link(dev_dir, vg_name, lv_name, dev, check_udev)) | ||||
| 			stack; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static DM_LIST_INIT(_fs_ops); | ||||
|  | ||||
| struct fs_op_parms { | ||||
| 	struct dm_list list; | ||||
| 	fs_op_t type; | ||||
| 	int check_udev; | ||||
| 	char *dev_dir; | ||||
| 	char *vg_name; | ||||
| 	char *lv_name; | ||||
| 	char *dev; | ||||
| 	char *old_lv_name; | ||||
| 	char names[0]; | ||||
| }; | ||||
|  | ||||
| static void _store_str(char **pos, char **ptr, const char *str) | ||||
| { | ||||
| 	strcpy(*pos, str); | ||||
| 	*ptr = *pos; | ||||
| 	*pos += strlen(*ptr) + 1; | ||||
| } | ||||
|  | ||||
| static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, | ||||
| 			const char *lv_name, const char *dev, | ||||
| 			const char *old_lv_name, int check_udev) | ||||
| { | ||||
| 	struct fs_op_parms *fsp; | ||||
| 	size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) + | ||||
| 	    strlen(dev) + strlen(old_lv_name) + 5; | ||||
| 	char *pos; | ||||
|  | ||||
| 	if (!(fsp = dm_malloc(sizeof(*fsp) + len))) { | ||||
| 		log_error("No space to stack fs operation"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	pos = fsp->names; | ||||
| 	fsp->type = type; | ||||
| 	fsp->check_udev = check_udev; | ||||
|  | ||||
| 	_store_str(&pos, &fsp->dev_dir, dev_dir); | ||||
| 	_store_str(&pos, &fsp->vg_name, vg_name); | ||||
| 	_store_str(&pos, &fsp->lv_name, lv_name); | ||||
| 	_store_str(&pos, &fsp->dev, dev); | ||||
| 	_store_str(&pos, &fsp->old_lv_name, old_lv_name); | ||||
|  | ||||
| 	dm_list_add(&_fs_ops, &fsp->list); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _pop_fs_ops(void) | ||||
| { | ||||
| 	struct dm_list *fsph, *fspht; | ||||
| 	struct fs_op_parms *fsp; | ||||
|  | ||||
| 	dm_list_iterate_safe(fsph, fspht, &_fs_ops) { | ||||
| 		fsp = dm_list_item(fsph, struct fs_op_parms); | ||||
| 		_do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name, | ||||
| 			  fsp->dev, fsp->old_lv_name, fsp->check_udev); | ||||
| 		dm_list_del(&fsp->list); | ||||
| 		dm_free(fsp); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, | ||||
| 		  const char *lv_name, const char *dev, const char *old_lv_name, | ||||
| 		  int check_udev) | ||||
| { | ||||
| 	if (memlock()) { | ||||
| 		if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev, | ||||
| 				  old_lv_name, check_udev)) | ||||
| 			return_0; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, | ||||
| 			 old_lv_name, check_udev); | ||||
| } | ||||
|  | ||||
| int fs_add_lv(const struct logical_volume *lv, const char *dev) | ||||
| { | ||||
| 	return _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, | ||||
| 		      dev, "", lv->vg->cmd->current_settings.udev_rules); | ||||
| } | ||||
|  | ||||
| int fs_del_lv(const struct logical_volume *lv) | ||||
| { | ||||
| 	return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, | ||||
| 		      "", "", lv->vg->cmd->current_settings.udev_rules); | ||||
| } | ||||
|  | ||||
| int fs_del_lv_byname(const char *dev_dir, const char *vg_name, | ||||
| 		     const char *lv_name, int check_udev) | ||||
| { | ||||
| 	return _fs_op(FS_DEL, dev_dir, vg_name, lv_name, "", "", check_udev); | ||||
| } | ||||
|  | ||||
| int fs_rename_lv(struct logical_volume *lv, const char *dev,  | ||||
| 		const char *old_vgname, const char *old_lvname) | ||||
| { | ||||
| 	if (strcmp(old_vgname, lv->vg->name)) { | ||||
| 		return | ||||
| 			(_fs_op(FS_DEL, lv->vg->cmd->dev_dir, old_vgname, | ||||
| 				old_lvname, "", "", lv->vg->cmd->current_settings.udev_rules) && | ||||
| 			 _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, | ||||
| 				lv->name, dev, "", lv->vg->cmd->current_settings.udev_rules)); | ||||
| 	} | ||||
| 	else  | ||||
| 		return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, | ||||
| 			      dev, old_lvname, lv->vg->cmd->current_settings.udev_rules); | ||||
| } | ||||
|  | ||||
| void fs_unlock(void) | ||||
| { | ||||
| 	if (!memlock()) { | ||||
| 		log_debug("Syncing device names"); | ||||
| 		/* Wait for all processed udev devices */ | ||||
| 		if (!dm_udev_wait(_fs_cookie)) | ||||
| 			stack; | ||||
| 		_fs_cookie = DM_COOKIE_AUTO_CREATE; /* Reset cookie */ | ||||
| 		dm_lib_release(); | ||||
| 		_pop_fs_ops(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| uint32_t fs_get_cookie(void) | ||||
| { | ||||
| 	return _fs_cookie; | ||||
| } | ||||
|  | ||||
| void fs_set_cookie(uint32_t cookie) | ||||
| { | ||||
| 	_fs_cookie = cookie; | ||||
| } | ||||
							
								
								
									
										36
									
								
								lib/activate/fs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								lib/activate/fs.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-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 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_FS_H | ||||
| #define _LVM_FS_H | ||||
|  | ||||
| #include "metadata.h" | ||||
|  | ||||
| /* | ||||
|  * These calls, private to the activate unit, set | ||||
|  * up the volume group directory in /dev and the | ||||
|  * symbolic links to the dm device. | ||||
|  */ | ||||
| int fs_add_lv(const struct logical_volume *lv, const char *dev); | ||||
| int fs_del_lv(const struct logical_volume *lv); | ||||
| int fs_del_lv_byname(const char *dev_dir, const char *vg_name, | ||||
| 		     const char *lv_name, int check_udev); | ||||
| int fs_rename_lv(struct logical_volume *lv, const char *dev,  | ||||
| 		 const char *old_vgname, const char *old_lvname); | ||||
| /* void fs_unlock(void);  moved to activate.h */ | ||||
| uint32_t fs_get_cookie(void); | ||||
| void fs_set_cookie(uint32_t cookie); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										32
									
								
								lib/activate/targets.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/activate/targets.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2006 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_TARGETS_H | ||||
| #define _LVM_TARGETS_H | ||||
|  | ||||
| struct dev_manager; | ||||
| struct lv_segment; | ||||
|  | ||||
| int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, | ||||
| 		       char *params, size_t paramsize, int *pos, | ||||
| 		       int start_area, int areas); | ||||
|  | ||||
| int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, | ||||
|                    struct dm_tree_node *node, uint32_t start_area, uint32_t areas); | ||||
|  | ||||
| int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf, | ||||
| 		     size_t bufsize, const char *desc); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1459
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1459
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										127
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								lib/cache/lvmcache.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2008 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_CACHE_H | ||||
| #define _LVM_CACHE_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
| #include "uuid.h" | ||||
| #include "label.h" | ||||
| #include "locking.h" | ||||
|  | ||||
| #define ORPHAN_PREFIX VG_ORPHANS | ||||
| #define ORPHAN_VG_NAME(fmt) ORPHAN_PREFIX "_" fmt | ||||
|  | ||||
| #define CACHE_INVALID	0x00000001 | ||||
| #define CACHE_LOCKED	0x00000002 | ||||
|  | ||||
| /* LVM specific per-volume info */ | ||||
| /* Eventual replacement for struct physical_volume perhaps? */ | ||||
|  | ||||
| struct cmd_context; | ||||
| struct format_type; | ||||
| struct volume_group; | ||||
| struct config_tree; | ||||
|  | ||||
| /* One per VG */ | ||||
| struct lvmcache_vginfo { | ||||
| 	struct dm_list list;	/* Join these vginfos together */ | ||||
| 	struct dm_list infos;	/* List head for lvmcache_infos */ | ||||
| 	const struct format_type *fmt; | ||||
| 	char *vgname;		/* "" == orphan */ | ||||
| 	uint32_t status; | ||||
| 	char vgid[ID_LEN + 1]; | ||||
| 	char _padding[7]; | ||||
| 	struct lvmcache_vginfo *next; /* Another VG with same name? */ | ||||
| 	char *creation_host; | ||||
| 	char *vgmetadata;	/* Copy of VG metadata as format_text string */ | ||||
| 	struct config_tree *cft; /* Config tree created from vgmetadata */ | ||||
| 				/* Lifetime is directly tied to vgmetadata */ | ||||
| 	unsigned precommitted;	/* Is vgmetadata live or precommitted? */ | ||||
| }; | ||||
|  | ||||
| /* One per device */ | ||||
| struct lvmcache_info { | ||||
| 	struct dm_list list;	/* Join VG members together */ | ||||
| 	struct dm_list mdas;	/* list head for metadata areas */ | ||||
| 	struct dm_list das;	/* list head for data areas */ | ||||
| 	struct lvmcache_vginfo *vginfo;	/* NULL == unknown */ | ||||
| 	struct label *label; | ||||
| 	const struct format_type *fmt; | ||||
| 	struct device *dev; | ||||
| 	uint64_t device_size;	/* Bytes */ | ||||
| 	uint32_t status; | ||||
| }; | ||||
|  | ||||
| int lvmcache_init(void); | ||||
| void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans); | ||||
|  | ||||
| /* Set full_scan to 1 to reread every filtered device label or | ||||
|  * 2 to rescan /dev for new devices */ | ||||
| int lvmcache_label_scan(struct cmd_context *cmd, int full_scan); | ||||
|  | ||||
| /* Add/delete a device */ | ||||
| struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, | ||||
| 				   struct device *dev, | ||||
| 				   const char *vgname, const char *vgid, | ||||
| 				   uint32_t vgstatus); | ||||
| int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt); | ||||
| void lvmcache_del(struct lvmcache_info *info); | ||||
|  | ||||
| /* Update things */ | ||||
| int lvmcache_update_vgname_and_id(struct lvmcache_info *info, | ||||
| 				  const char *vgname, const char *vgid, | ||||
| 				  uint32_t vgstatus, const char *hostname); | ||||
| int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted); | ||||
|  | ||||
| void lvmcache_lock_vgname(const char *vgname, int read_only); | ||||
| void lvmcache_unlock_vgname(const char *vgname); | ||||
| int lvmcache_verify_lock_order(const char *vgname); | ||||
|  | ||||
| /* Queries */ | ||||
| const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid, unsigned revalidate_labels); | ||||
| struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, | ||||
| 					   const char *vgid); | ||||
| struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid); | ||||
| struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only); | ||||
| const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid); | ||||
| struct device *device_from_pvid(struct cmd_context *cmd, const struct id *pvid, | ||||
| 				unsigned *scan_done_once); | ||||
| const char *pvid_from_devname(struct cmd_context *cmd, | ||||
| 			      const char *dev_name); | ||||
| char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid); | ||||
| int vgs_locked(void); | ||||
| int vgname_is_locked(const char *vgname); | ||||
|  | ||||
| /* Returns list of struct str_lists containing pool-allocated copy of vgnames */ | ||||
| /* If include_internal is not set, return only proper vg names. */ | ||||
| struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd, | ||||
| 				     int include_internal); | ||||
|  | ||||
| /* Returns list of struct str_lists containing pool-allocated copy of vgids */ | ||||
| /* If include_internal is not set, return only proper vg ids. */ | ||||
| struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, | ||||
| 				   int include_internal); | ||||
|  | ||||
| /* Returns list of struct str_lists containing pool-allocated copy of pvids */ | ||||
| struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname, | ||||
| 				const char *vgid); | ||||
|  | ||||
| /* Returns cached volume group metadata. */ | ||||
| struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted); | ||||
| void lvmcache_drop_metadata(const char *vgname, int drop_precommitted); | ||||
| void lvmcache_commit_metadata(const char *vgname); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										26
									
								
								lib/commands/errors.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								lib/commands/errors.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-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 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_ERRORS_H | ||||
| #define _LVM_ERRORS_H | ||||
|  | ||||
| #define ECMD_PROCESSED		1 | ||||
| #define ENO_SUCH_CMD		2 | ||||
| #define EINVALID_CMD_LINE	3 | ||||
| #define ECMD_FAILED		5 | ||||
|  | ||||
| /* FIXME Also returned by cmdlib. */ | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1400
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1400
									
								
								lib/commands/toolcontext.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										121
									
								
								lib/commands/toolcontext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								lib/commands/toolcontext.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_TOOLCONTEXT_H | ||||
| #define _LVM_TOOLCONTEXT_H | ||||
|  | ||||
| #include "dev-cache.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <limits.h> | ||||
|  | ||||
| /* | ||||
|  * Config options that can be changed while commands are processed | ||||
|  */ | ||||
| struct config_info { | ||||
| 	int debug; | ||||
| 	int verbose; | ||||
| 	int test; | ||||
| 	int syslog; | ||||
| 	int activation; | ||||
| 	int suffix; | ||||
| 	int archive;		/* should we archive ? */ | ||||
| 	int backup;		/* should we backup ? */ | ||||
| 	int read_ahead;		/* DM_READ_AHEAD_NONE or _AUTO */ | ||||
| 	int udev_rules; | ||||
| 	int udev_sync; | ||||
| 	int cache_vgmetadata; | ||||
| 	const char *msg_prefix; | ||||
| 	const char *fmt_name; | ||||
| 	uint64_t unit_factor; | ||||
| 	int cmd_name;		/* Show command name? */ | ||||
| 	mode_t umask; | ||||
| 	char unit_type; | ||||
| 	char _padding[1]; | ||||
| }; | ||||
|  | ||||
| struct config_tree; | ||||
| struct archive_params; | ||||
| struct backup_params; | ||||
| struct arg_values; | ||||
|  | ||||
| /* FIXME Split into tool & library contexts */ | ||||
| /* command-instance-related variables needed by library */ | ||||
| struct cmd_context { | ||||
| 	struct dm_pool *libmem;	/* For permanent config data */ | ||||
| 	struct dm_pool *mem;	/* Transient: Cleared between each command */ | ||||
|  | ||||
| 	const struct format_type *fmt;	/* Current format to use by default */ | ||||
| 	struct format_type *fmt_backup;	/* Format to use for backups */ | ||||
|  | ||||
| 	struct dm_list formats;	/* Available formats */ | ||||
| 	struct dm_list segtypes;	/* Available segment types */ | ||||
| 	const char *hostname; | ||||
| 	const char *kernel_vsn; | ||||
|  | ||||
| 	unsigned rand_seed; | ||||
| 	const char *cmd_line; | ||||
| 	struct command *command; | ||||
| 	char **argv; | ||||
| 	struct arg_values *arg_values; | ||||
| 	struct dm_list arg_value_groups; | ||||
| 	unsigned is_long_lived:1;	/* Optimises persistent_filter handling */ | ||||
| 	unsigned handles_missing_pvs:1; | ||||
| 	unsigned handles_unknown_segments:1; | ||||
| 	unsigned partial_activation:1; | ||||
| 	unsigned si_unit_consistency:1; | ||||
| 	unsigned metadata_read_only:1; | ||||
|  | ||||
| 	unsigned independent_metadata_areas:1;	/* Active formats have MDAs outside PVs */ | ||||
|  | ||||
| 	struct dev_filter *filter; | ||||
| 	int dump_filter;	/* Dump filter when exiting? */ | ||||
|  | ||||
| 	struct dm_list config_files; | ||||
| 	int config_valid; | ||||
| 	struct config_tree *cft; | ||||
| 	struct config_tree *cft_override; | ||||
| 	struct config_info default_settings; | ||||
| 	struct config_info current_settings; | ||||
|  | ||||
| 	struct archive_params *archive_params; | ||||
| 	struct backup_params *backup_params; | ||||
| 	const char *stripe_filler; | ||||
|  | ||||
| 	/* List of defined tags */ | ||||
| 	struct dm_list tags; | ||||
| 	int hosttags; | ||||
|  | ||||
| 	char system_dir[PATH_MAX]; | ||||
| 	char dev_dir[PATH_MAX]; | ||||
| 	char proc_dir[PATH_MAX]; | ||||
| 	char sysfs_dir[PATH_MAX]; /* FIXME Use global value instead. */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * system_dir may be NULL to use the default value. | ||||
|  * The environment variable LVM_SYSTEM_DIR always takes precedence. | ||||
|  */ | ||||
| struct cmd_context *create_toolcontext(unsigned is_long_lived, | ||||
| 				       const char *system_dir); | ||||
| void destroy_toolcontext(struct cmd_context *cmd); | ||||
| int refresh_toolcontext(struct cmd_context *cmd); | ||||
| int refresh_filters(struct cmd_context *cmd); | ||||
| int config_files_changed(struct cmd_context *cmd); | ||||
| int init_lvmcache_orphans(struct cmd_context *cmd); | ||||
|  | ||||
| struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1382
									
								
								lib/config/config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1382
									
								
								lib/config/config.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										123
									
								
								lib/config/config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								lib/config/config.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-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 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_CONFIG_H | ||||
| #define _LVM_CONFIG_H | ||||
|  | ||||
| #include "lvm-types.h" | ||||
|  | ||||
| struct device; | ||||
| struct cmd_context; | ||||
|  | ||||
| enum { | ||||
| 	CFG_STRING, | ||||
| 	CFG_FLOAT, | ||||
| 	CFG_INT, | ||||
| 	CFG_EMPTY_ARRAY | ||||
| }; | ||||
|  | ||||
| struct config_value { | ||||
| 	int type; | ||||
| 	union { | ||||
| 		int64_t i; | ||||
| 		float r; | ||||
| 		const char *str; | ||||
| 	} v; | ||||
| 	struct config_value *next;	/* for arrays */ | ||||
| }; | ||||
|  | ||||
| struct config_node { | ||||
| 	const char *key; | ||||
| 	struct config_node *parent, *sib, *child; | ||||
| 	struct config_value *v; | ||||
| }; | ||||
|  | ||||
| struct config_tree { | ||||
| 	struct config_node *root; | ||||
| }; | ||||
|  | ||||
| struct config_tree_list { | ||||
| 	struct dm_list list; | ||||
| 	struct config_tree *cft; | ||||
| }; | ||||
|  | ||||
| struct config_tree *create_config_tree(const char *filename, int keep_open); | ||||
| struct config_tree *create_config_tree_from_string(struct cmd_context *cmd, | ||||
| 						   const char *config_settings); | ||||
| int override_config_tree_from_string(struct cmd_context *cmd, | ||||
| 				     const char *config_settings); | ||||
| void destroy_config_tree(struct config_tree *cft); | ||||
|  | ||||
| typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_t size); | ||||
|  | ||||
| int read_config_fd(struct config_tree *cft, struct device *dev, | ||||
| 		   off_t offset, size_t size, off_t offset2, size_t size2, | ||||
| 		   checksum_fn_t checksum_fn, uint32_t checksum); | ||||
|  | ||||
| int read_config_file(struct config_tree *cft); | ||||
| int write_config_file(struct config_tree *cft, const char *file, | ||||
| 		      int argc, char **argv); | ||||
|  | ||||
| typedef int (*putline_fn)(const char *line, void *baton); | ||||
| int write_config_node(const struct config_node *cn, putline_fn putline, void *baton); | ||||
|  | ||||
| time_t config_file_timestamp(struct config_tree *cft); | ||||
| int config_file_changed(struct config_tree *cft); | ||||
| int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft, | ||||
| 		      struct config_tree *newdata); | ||||
|  | ||||
| const struct config_node *find_config_node(const struct config_node *cn, | ||||
| 					   const char *path); | ||||
| const char *find_config_str(const struct config_node *cn, const char *path, | ||||
| 			    const char *fail); | ||||
| int find_config_int(const struct config_node *cn, const char *path, int fail); | ||||
| float find_config_float(const struct config_node *cn, const char *path, | ||||
| 			float fail); | ||||
|  | ||||
| /* | ||||
|  * These versions check an override tree, if present, first. | ||||
|  */ | ||||
| const struct config_node *find_config_tree_node(struct cmd_context *cmd, | ||||
| 						const char *path); | ||||
| const char *find_config_tree_str(struct cmd_context *cmd, | ||||
| 				 const char *path, const char *fail); | ||||
| int find_config_tree_int(struct cmd_context *cmd, const char *path, | ||||
| 			 int fail); | ||||
| float find_config_tree_float(struct cmd_context *cmd, const char *path, | ||||
| 			     float fail); | ||||
|  | ||||
| /* | ||||
|  * Understands (0, ~0), (y, n), (yes, no), (on, | ||||
|  * off), (true, false). | ||||
|  */ | ||||
| int find_config_bool(const struct config_node *cn, const char *path, int fail); | ||||
| int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail); | ||||
|  | ||||
| int get_config_uint32(const struct config_node *cn, const char *path, | ||||
| 		      uint32_t *result); | ||||
|  | ||||
| int get_config_uint64(const struct config_node *cn, const char *path, | ||||
| 		      uint64_t *result); | ||||
|  | ||||
| int get_config_str(const struct config_node *cn, const char *path, | ||||
| 		   const char **result); | ||||
|  | ||||
| unsigned maybe_config_section(const char *str, unsigned len); | ||||
|  | ||||
| const char *config_parent_name(const struct config_node *n); | ||||
|  | ||||
| struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn, | ||||
| 				      int siblings); | ||||
| #endif | ||||
							
								
								
									
										155
									
								
								lib/config/defaults.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								lib/config/defaults.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_DEFAULTS_H | ||||
| #define _LVM_DEFAULTS_H | ||||
|  | ||||
| #define DEFAULT_PE_ALIGN 2048 | ||||
| #define DEFAULT_PE_ALIGN_OLD 128 | ||||
|  | ||||
| #define DEFAULT_ARCHIVE_ENABLED 1 | ||||
| #define DEFAULT_BACKUP_ENABLED 1 | ||||
|  | ||||
| #define DEFAULT_CACHE_FILE_PREFIX "" | ||||
|  | ||||
| #define DEFAULT_ARCHIVE_DAYS 30 | ||||
| #define DEFAULT_ARCHIVE_NUMBER 10 | ||||
|  | ||||
| #define DEFAULT_DEV_DIR "/dev" | ||||
| #define DEFAULT_PROC_DIR "/proc" | ||||
| #define DEFAULT_SYSFS_SCAN 1 | ||||
| #define DEFAULT_MD_COMPONENT_DETECTION 1 | ||||
| #define DEFAULT_MD_CHUNK_ALIGNMENT 1 | ||||
| #define DEFAULT_IGNORE_SUSPENDED_DEVICES 1 | ||||
| #define DEFAULT_DISABLE_AFTER_ERROR_COUNT 0 | ||||
| #define DEFAULT_REQUIRE_RESTOREFILE_WITH_UUID 1 | ||||
| #define DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION 1 | ||||
| #define DEFAULT_DATA_ALIGNMENT_DETECTION 1 | ||||
|  | ||||
| #define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so" | ||||
| #define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1 | ||||
| #define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1 | ||||
| #define DEFAULT_WAIT_FOR_LOCKS 1 | ||||
| #define DEFAULT_PRIORITISE_WRITE_LOCKS 1 | ||||
| #define DEFAULT_USE_MLOCKALL 0 | ||||
| #define DEFAULT_METADATA_READ_ONLY 0 | ||||
|  | ||||
| #define DEFAULT_MIRRORLOG "disk" | ||||
| #define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate" | ||||
| #define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove" | ||||
| #define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */ | ||||
| #define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so" | ||||
| #define DEFAULT_DMEVENTD_SNAPSHOT_LIB "libdevmapper-event-lvm2snapshot.so" | ||||
| #define DEFAULT_DMEVENTD_MONITOR 1 | ||||
| #define DEFAULT_BACKGROUND_POLLING 1 | ||||
|  | ||||
| #define DEFAULT_UMASK 0077 | ||||
|  | ||||
| #ifdef LVM1_FALLBACK | ||||
| #  define DEFAULT_FALLBACK_TO_LVM1 1 | ||||
| #else | ||||
| #  define DEFAULT_FALLBACK_TO_LVM1 0 | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_FORMAT "lvm2" | ||||
|  | ||||
| #define DEFAULT_STRIPESIZE 64	/* KB */ | ||||
| #define DEFAULT_PVMETADATAIGNORE 0 | ||||
| #define DEFAULT_PVMETADATAIGNORE_STR "n" | ||||
| #define DEFAULT_PVMETADATASIZE 255 | ||||
| #define DEFAULT_PVMETADATACOPIES 1 | ||||
| #define DEFAULT_VGMETADATACOPIES 0 | ||||
| #define DEFAULT_LABELSECTOR UINT64_C(1) | ||||
| #define DEFAULT_READ_AHEAD "auto" | ||||
| #define DEFAULT_UDEV_RULES 1 | ||||
| #define DEFAULT_UDEV_SYNC 0 | ||||
| #define DEFAULT_EXTENT_SIZE 4096	/* In KB */ | ||||
| #define DEFAULT_MAX_PV 0 | ||||
| #define DEFAULT_MAX_LV 0 | ||||
| #define DEFAULT_ALLOC_POLICY ALLOC_NORMAL | ||||
| #define DEFAULT_CLUSTERED 0 | ||||
|  | ||||
| #define DEFAULT_MSG_PREFIX "  " | ||||
| #define DEFAULT_CMD_NAME 0 | ||||
| #define DEFAULT_OVERWRITE 0 | ||||
|  | ||||
| #ifndef DEFAULT_LOG_FACILITY | ||||
| #  define DEFAULT_LOG_FACILITY LOG_USER | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_SYSLOG 1 | ||||
| #define DEFAULT_VERBOSE 0 | ||||
| #define DEFAULT_LOGLEVEL 0 | ||||
| #define DEFAULT_INDENT 1 | ||||
| #define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0 | ||||
| #define DEFAULT_UNITS "h" | ||||
| #define DEFAULT_SUFFIX 1 | ||||
| #define DEFAULT_HOSTTAGS 0 | ||||
|  | ||||
| #ifndef DEFAULT_SI_UNIT_CONSISTENCY | ||||
| #  define DEFAULT_SI_UNIT_CONSISTENCY 1 | ||||
| #endif | ||||
|  | ||||
| #ifdef DEVMAPPER_SUPPORT | ||||
| #  define DEFAULT_ACTIVATION 1 | ||||
| #  define DEFAULT_RESERVED_MEMORY 8192 | ||||
| #  define DEFAULT_RESERVED_STACK 256 | ||||
| #  define DEFAULT_PROCESS_PRIORITY -18 | ||||
| #else | ||||
| #  define DEFAULT_ACTIVATION 0 | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_STRIPE_FILLER "error" | ||||
| #define DEFAULT_MIRROR_REGION_SIZE 512	/* KB */ | ||||
| #define DEFAULT_INTERVAL 15 | ||||
|  | ||||
| #ifdef READLINE_SUPPORT | ||||
| #  define DEFAULT_MAX_HISTORY 100 | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_MAX_ERROR_COUNT	NO_DEV_ERROR_COUNT_LIMIT | ||||
|  | ||||
| #define DEFAULT_REP_ALIGNED 1 | ||||
| #define DEFAULT_REP_BUFFERED 1 | ||||
| #define DEFAULT_REP_COLUMNS_AS_ROWS 0 | ||||
| #define DEFAULT_REP_HEADINGS 1 | ||||
| #define DEFAULT_REP_PREFIXES 0 | ||||
| #define DEFAULT_REP_QUOTED 1 | ||||
| #define DEFAULT_REP_SEPARATOR " " | ||||
|  | ||||
| #define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,mirror_log,copy_percent,convert_lv" | ||||
| #define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free" | ||||
| #define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free" | ||||
| #define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size" | ||||
| #define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size" | ||||
|  | ||||
| #define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid" | ||||
| #define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid" | ||||
| #define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid" | ||||
| #define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize" | ||||
| #define DEFAULT_PVSEGS_COLS_VERB "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" | ||||
|  | ||||
| #define DEFAULT_LVS_SORT "vg_name,lv_name" | ||||
| #define DEFAULT_VGS_SORT "vg_name" | ||||
| #define DEFAULT_PVS_SORT "pv_name" | ||||
| #define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start" | ||||
| #define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start" | ||||
|  | ||||
| #define DEFAULT_MIRROR_DEVICE_FAULT_POLICY "remove" | ||||
| #define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate" | ||||
| #define DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD 100 | ||||
| #define DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT 20 | ||||
|  | ||||
| #endif				/* _LVM_DEFAULTS_H */ | ||||
							
								
								
									
										137
									
								
								lib/datastruct/btree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								lib/datastruct/btree.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-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 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 "btree.h" | ||||
|  | ||||
| struct node { | ||||
| 	uint32_t key; | ||||
| 	struct node *l, *r, *p; | ||||
|  | ||||
| 	void *data; | ||||
| }; | ||||
|  | ||||
| struct btree { | ||||
| 	struct dm_pool *mem; | ||||
| 	struct node *root; | ||||
| }; | ||||
|  | ||||
| struct btree *btree_create(struct dm_pool *mem) | ||||
| { | ||||
| 	struct btree *t = dm_pool_alloc(mem, sizeof(*t)); | ||||
|  | ||||
| 	if (t) { | ||||
| 		t->mem = mem; | ||||
| 		t->root = NULL; | ||||
| 	} | ||||
|  | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Shuffle the bits in a key, to try and remove | ||||
|  * any ordering. | ||||
|  */ | ||||
| static uint32_t _shuffle(uint32_t k) | ||||
| { | ||||
| #if 1 | ||||
| 	return ((k & 0xff) << 24 | | ||||
| 		(k & 0xff00) << 8 | | ||||
| 		(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24); | ||||
| #else | ||||
| 	return k; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static struct node **_lookup(struct node *const *c, uint32_t key, | ||||
| 			     struct node **p) | ||||
| { | ||||
| 	*p = NULL; | ||||
| 	while (*c) { | ||||
| 		*p = *c; | ||||
| 		if ((*c)->key == key) | ||||
| 			break; | ||||
|  | ||||
| 		if (key < (*c)->key) | ||||
| 			c = &(*c)->l; | ||||
|  | ||||
| 		else | ||||
| 			c = &(*c)->r; | ||||
| 	} | ||||
|  | ||||
| 	return (struct node **)c; | ||||
| } | ||||
|  | ||||
| void *btree_lookup(const struct btree *t, uint32_t k) | ||||
| { | ||||
| 	uint32_t key = _shuffle(k); | ||||
| 	struct node *p, **c = _lookup(&t->root, key, &p); | ||||
| 	return (*c) ? (*c)->data : NULL; | ||||
| } | ||||
|  | ||||
| int btree_insert(struct btree *t, uint32_t k, void *data) | ||||
| { | ||||
| 	uint32_t key = _shuffle(k); | ||||
| 	struct node *p, **c = _lookup(&t->root, key, &p), *n; | ||||
|  | ||||
| 	if (!*c) { | ||||
| 		if (!(n = dm_pool_alloc(t->mem, sizeof(*n)))) | ||||
| 			return_0; | ||||
|  | ||||
| 		n->key = key; | ||||
| 		n->data = data; | ||||
| 		n->l = n->r = NULL; | ||||
| 		n->p = p; | ||||
|  | ||||
| 		*c = n; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void *btree_get_data(const struct btree_iter *it) | ||||
| { | ||||
| 	return ((const struct node *) it)->data; | ||||
| } | ||||
|  | ||||
| static struct node *_left(struct node *n) | ||||
| { | ||||
| 	while (n->l) | ||||
| 		n = n->l; | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| struct btree_iter *btree_first(const struct btree *t) | ||||
| { | ||||
| 	if (!t->root) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return (struct btree_iter *) _left(t->root); | ||||
| } | ||||
|  | ||||
| struct btree_iter *btree_next(const struct btree_iter *it) | ||||
| { | ||||
| 	struct node *n = (struct node *) it; | ||||
| 	uint32_t k = n->key; | ||||
|  | ||||
| 	if (n->r) | ||||
| 		return (struct btree_iter *) _left(n->r); | ||||
|  | ||||
| 	do | ||||
| 		n = n->p; | ||||
| 	while (n && k > n->key); | ||||
|  | ||||
| 	return (struct btree_iter *) n; | ||||
| } | ||||
							
								
								
									
										32
									
								
								lib/datastruct/btree.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/datastruct/btree.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2005 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_BTREE_H | ||||
| #define _LVM_BTREE_H | ||||
|  | ||||
| struct btree; | ||||
|  | ||||
| struct btree *btree_create(struct dm_pool *mem); | ||||
|  | ||||
| void *btree_lookup(const struct btree *t, uint32_t k); | ||||
| int btree_insert(struct btree *t, uint32_t k, void *data); | ||||
|  | ||||
| struct btree_iter; | ||||
| void *btree_get_data(const struct btree_iter *it); | ||||
|  | ||||
| struct btree_iter *btree_first(const struct btree *t); | ||||
| struct btree_iter *btree_next(const struct btree_iter *it); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										32
									
								
								lib/datastruct/lvm-types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/datastruct/lvm-types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-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 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_TYPES_H | ||||
| #define _LVM_TYPES_H | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <inttypes.h> | ||||
|  | ||||
| /* Define some portable printing types */ | ||||
| #define PRIsize_t "zu" | ||||
| #define PRIptrdiff_t "td" | ||||
| #define PRIpid_t PRId32 | ||||
|  | ||||
| struct str_list { | ||||
| 	struct dm_list list; | ||||
| 	const char *str; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										127
									
								
								lib/datastruct/str_list.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								lib/datastruct/str_list.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. | ||||
|  * Copyright (C) 2004-2005 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 "str_list.h" | ||||
|  | ||||
| struct dm_list *str_list_create(struct dm_pool *mem) | ||||
| { | ||||
| 	struct dm_list *sl; | ||||
|  | ||||
| 	if (!(sl = dm_pool_alloc(mem, sizeof(struct dm_list)))) { | ||||
| 		log_errno(ENOMEM, "str_list allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	dm_list_init(sl); | ||||
|  | ||||
| 	return sl; | ||||
| } | ||||
|  | ||||
| int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str) | ||||
| { | ||||
| 	struct str_list *sln; | ||||
|  | ||||
| 	if (!str) | ||||
| 		return_0; | ||||
|  | ||||
| 	/* Already in list? */ | ||||
| 	if (str_list_match_item(sll, str)) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!(sln = dm_pool_alloc(mem, sizeof(*sln)))) | ||||
| 		return_0; | ||||
|  | ||||
| 	sln->str = str; | ||||
| 	dm_list_add(sll, &sln->list); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int str_list_del(struct dm_list *sll, const char *str) | ||||
| { | ||||
| 	struct dm_list *slh, *slht; | ||||
|  | ||||
| 	dm_list_iterate_safe(slh, slht, sll) { | ||||
| 		if (!strcmp(str, dm_list_item(slh, struct str_list)->str)) | ||||
| 			 dm_list_del(slh); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew, | ||||
| 		 const struct dm_list *sllold) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	dm_list_init(sllnew); | ||||
|  | ||||
| 	dm_list_iterate_items(sl, sllold) { | ||||
| 		if (!str_list_add(mem, sllnew, dm_pool_strdup(mem, sl->str))) | ||||
| 			return_0; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is item on list? | ||||
|  */ | ||||
| int str_list_match_item(const struct dm_list *sll, const char *str) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	dm_list_iterate_items(sl, sll) | ||||
| 	    if (!strcmp(str, sl->str)) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Is at least one item on both lists? | ||||
|  * If tag_matched is non-NULL, it is set to the tag that matched. | ||||
|  */ | ||||
| int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2, const char **tag_matched) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	dm_list_iterate_items(sl, sll) | ||||
| 		if (str_list_match_item(sll2, sl->str)) { | ||||
| 			if (tag_matched) | ||||
| 				*tag_matched = sl->str; | ||||
| 			return 1; | ||||
| 		} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Do both lists contain the same set of items? | ||||
|  */ | ||||
| int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2) | ||||
| { | ||||
| 	struct str_list *sl; | ||||
|  | ||||
| 	if (dm_list_size(sll) != dm_list_size(sll2)) | ||||
| 		return 0; | ||||
|  | ||||
| 	dm_list_iterate_items(sl, sll) | ||||
| 	    if (!str_list_match_item(sll2, sl->str)) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user